{"thread":{"id":"43877","subject":"[PATCH 3/4] cat-file --textconv/--filters: allow specifying the path separately","startedAt":"2016-08-18T12:48:19Z","lastAt":"2016-09-11T21:44:55Z","messageCount":66,"participants":["Johannes Schindelin","Junio C Hamano","Torsten Bögershausen","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"299601","messageId":"787224ce9a382ddd1180a408e784ca26993e5603.1471524357.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1471524357.git.johannes.schindelin@gmx.de","subject":"[PATCH 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-18T12:46:23Z","receivedAt":"2016-08-18T12:48:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There are circumstances when it is relatively easy to figure out the\nobject name for a given path, but not the revision. For example, when\nlooking at a diff generated by Git, the object names are recorded, but\nnot the revision. As a matter of fact, the revisions from which the diff\nwas generated may not even exist locally.\n\nIn such a case, the user would have to generate a fake revision just to\nbe able to use --textconv or --filters.\n\nLet's simplify this dramatically, because we do not really need that\nrevision at all: all we care about is that we know the path. In the\nscenario described above, we do know the path, and we just want to\nspecify it separately from the object name.\n\nExample usage:\n\n\tgit cat-file --textconv --use-path=main.c 0f1937fd\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt |  7 ++++++-\n builtin/cat-file.c             | 22 +++++++++++++++++-----\n t/t8010-cat-file-filters.sh    | 13 +++++++++++++\n 3 files changed, 36 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 7d48735..59a3c37 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -9,7 +9,7 @@ git-cat-file - Provide content or type and size information for repository objec\n SYNOPSIS\n --------\n [verse]\n-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--use-path=<path>] <object>\n 'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n \n DESCRIPTION\n@@ -64,6 +64,11 @@ OPTIONS\n \tend-of-line conversion, etc). In this case, <object> has to be of\n \tthe form <tree-ish>:<path>, or :<path>.\n \n+--use-path=<path>::\n+\tFor use with --textconv or --filters, to allow specifying an object\n+\tname and a path separately, e.g. when it is difficult to figure out\n+\tthe revision from which the blob came.\n+\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 0b74afa..5ff58b3 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -20,6 +20,8 @@ struct batch_options {\n \tconst char *format;\n };\n \n+static const char *force_path;\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const unsigned char *sha1,\n \t\t\t char **buf, unsigned long *size)\n@@ -89,21 +91,24 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\treturn !has_sha1_file(sha1);\n \n \tcase 'w':\n-\t\tif (!obj_context.path[0])\n+\t\tif (!force_path && !obj_context.path[0])\n \t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n \t\t\t    \"<sha1:path>\", obj_name);\n \n-\t\tif (filter_object(obj_context.path, obj_context.mode,\n+\t\tif (filter_object(force_path ? force_path : obj_context.path,\n+\t\t\t\t  force_path ? 0100644 : obj_context.mode,\n \t\t\t\t  sha1, &buf, &size))\n \t\t\treturn -1;\n \t\tbreak;\n \n \tcase 'c':\n-\t\tif (!obj_context.path[0])\n+\t\tif (!force_path && !obj_context.path[0])\n \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n \t\t\t    obj_name);\n \n-\t\tif (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))\n+\t\tif (textconv_object(force_path ? force_path : obj_context.path,\n+\t\t\t\t    force_path ? 0100644 : obj_context.mode,\n+\t\t\t\t    sha1, 1, &buf, &size))\n \t\t\tbreak;\n \n \tcase 'p':\n@@ -477,7 +482,7 @@ static int batch_objects(struct batch_options *opt)\n }\n \n static const char * const cat_file_usage[] = {\n-\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) <object>\"),\n+\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--use-path=<path>] <object>\"),\n \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n \tNULL\n };\n@@ -525,6 +530,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n \t\tOPT_CMDMODE(0, \"filters\", &opt,\n \t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n+\t\tOPT_STRING(0, \"use-path\", &force_path, N_(\"blob\"),\n+\t\t\t   N_(\"use a specific path for --textconv/--filters\")),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\n@@ -567,6 +574,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(cat_file_usage, options);\n \t}\n \n+\tif (force_path && opt != 'c' && opt != 'w') {\n+\t\terror(\"--use-path=<path> needs --textconv or --filters\");\n+\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\n \tif (batch.buffer_output < 0)\n \t\tbatch.buffer_output = batch.all_objects;\n \ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nindex e466634..fd17159 100755\n--- a/t/t8010-cat-file-filters.sh\n+++ b/t/t8010-cat-file-filters.sh\n@@ -31,4 +31,17 @@ test_expect_success 'cat-file --filters converts to worktree version' '\n \thas_cr actual\n '\n \n+test_expect_success 'cat-file --filters --use-path=<path> works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\tgit cat-file --filters --use-path=world.txt $sha1 >actual &&\n+\thas_cr actual\n+'\n+\n+test_expect_success 'cat-file --textconv --use-path=<path> works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n+\tgit cat-file --textconv --use-path=hello.txt $sha1 >rot13 &&\n+\ttest uryyb = \"$(cat rot13 | remove_cr)\"\n+'\n+\n test_done\n-- \n2.9.2.691.g78954f3\n\n\n"},{"id":"299602","messageId":"f1e188907f31abef9e82bd6b0da120ab7d9bd4a7.1471524357.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1471524357.git.johannes.schindelin@gmx.de","subject":"[PATCH 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-18T12:46:17Z","receivedAt":"2016-08-18T12:48:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As suggested by its name, the --filters option applies the filters\nthat are currently configured for the specified path.\n\nThis feature comes in handy when a 3rd-party tool wants to work with\nthe contents of files from past revisions as if they had been checked\nout, but without detouring via temporary files.\n\nNote that we ensure that symbolic links are unaffected (we know from\nlooking at the mode whether it refers to a symbolic link or a regular\nfile).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 12 +++++++++---\n builtin/cat-file.c             | 41 ++++++++++++++++++++++++++++++++++++++++-\n t/t8010-cat-file-filters.sh    | 34 ++++++++++++++++++++++++++++++++++\n 3 files changed, 83 insertions(+), 4 deletions(-)\n create mode 100755 t/t8010-cat-file-filters.sh\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 071029b..7d48735 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -9,15 +9,15 @@ git-cat-file - Provide content or type and size information for repository objec\n SYNOPSIS\n --------\n [verse]\n-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv ) <object>\n+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n 'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n \n DESCRIPTION\n -----------\n In its first form, the command provides the content or the type of an object in\n the repository. The type is required unless `-t` or `-p` is used to find the\n-object type, or `-s` is used to find the object size, or `--textconv` is used\n-(which implies type \"blob\").\n+object type, or `-s` is used to find the object size, or `--textconv` or\n+`--filters` is used (which imply type \"blob\").\n \n In the second form, a list of objects (separated by linefeeds) is provided on\n stdin, and the SHA-1, type, and size of each object is printed on stdout.\n@@ -58,6 +58,12 @@ OPTIONS\n \torder to apply the filter to the content recorded in the index at\n \t<path>.\n \n+--filters::\n+\tShow the content as transformed by the filters configured in\n+\tthe current working tree for the given <path> (i.e. smudge filters,\n+\tend-of-line conversion, etc). In this case, <object> has to be of\n+\tthe form <tree-ish>:<path>, or :<path>.\n+\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 2dfe626..0b74afa 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -20,6 +20,33 @@ struct batch_options {\n \tconst char *format;\n };\n \n+static int filter_object(const char *path, unsigned mode,\n+\t\t\t const unsigned char *sha1,\n+\t\t\t char **buf, unsigned long *size)\n+{\n+\tenum object_type type;\n+\n+\t*buf = read_sha1_file(sha1, &type, size);\n+\tif (!*buf)\n+\t\treturn error(_(\"cannot read object %s '%s'\"),\n+\t\t\tsha1_to_hex(sha1), path);\n+\tif (type != OBJ_BLOB) {\n+\t\tfree(*buf);\n+\t\treturn error(_(\"blob expected for %s '%s'\"),\n+\t\t\tsha1_to_hex(sha1), path);\n+\t}\n+\tif (S_ISREG(mode)) {\n+\t\tstruct strbuf strbuf = STRBUF_INIT;\n+\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n+\t\t\tfree(*buf);\n+\t\t\t*size = strbuf.len;\n+\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t\tint unknown_type)\n {\n@@ -61,6 +88,16 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tcase 'e':\n \t\treturn !has_sha1_file(sha1);\n \n+\tcase 'w':\n+\t\tif (!obj_context.path[0])\n+\t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n+\t\t\t    \"<sha1:path>\", obj_name);\n+\n+\t\tif (filter_object(obj_context.path, obj_context.mode,\n+\t\t\t\t  sha1, &buf, &size))\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n \tcase 'c':\n \t\tif (!obj_context.path[0])\n \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n@@ -440,7 +477,7 @@ static int batch_objects(struct batch_options *opt)\n }\n \n static const char * const cat_file_usage[] = {\n-\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv) <object>\"),\n+\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) <object>\"),\n \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n \tNULL\n };\n@@ -486,6 +523,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('p', NULL, &opt, N_(\"pretty-print object's content\"), 'p'),\n \t\tOPT_CMDMODE(0, \"textconv\", &opt,\n \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n+\t\tOPT_CMDMODE(0, \"filters\", &opt,\n+\t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nnew file mode 100755\nindex 0000000..e466634\n--- /dev/null\n+++ b/t/t8010-cat-file-filters.sh\n@@ -0,0 +1,34 @@\n+#!/bin/sh\n+\n+test_description='git cat-file filters support'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup ' '\n+\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n+\techo \"hello\" | append_cr >world.txt &&\n+\tgit add .gitattributes world.txt &&\n+\ttest_tick &&\n+\tgit commit -m \"Initial commit\"\n+'\n+\n+has_cr () {\n+\ttr '\\015' Q <\"$1\" | grep Q >/dev/null\n+}\n+\n+test_expect_success 'no filters with `git show`' '\n+\tgit show HEAD:world.txt >actual &&\n+\t! has_cr actual\n+\n+'\n+\n+test_expect_success 'no filters with cat-file' '\n+\tgit cat-file blob HEAD:world.txt >actual &&\n+\t! has_cr actual\n+'\n+\n+test_expect_success 'cat-file --filters converts to worktree version' '\n+\tgit cat-file --filters HEAD:world.txt >actual &&\n+\thas_cr actual\n+'\n+\n+test_done\n-- \n2.9.2.691.g78954f3\n\n\n"},{"id":"299603","messageId":"2315ae5ab6918a7c1567f11a64093a860983bc20.1471524357.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1471524357.git.johannes.schindelin@gmx.de","subject":"[PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-18T12:46:28Z","receivedAt":"2016-08-18T12:48:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"With this patch, --batch can be combined with --textconv or --filters.\nFor this to work, the input needs to have the form\n\n\t<object name><single white space><path>\n\nso that the filters can be chosen appropriately.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 18 +++++++++++-----\n builtin/cat-file.c             | 49 +++++++++++++++++++++++++++++++++++++-----\n t/t8010-cat-file-filters.sh    | 10 +++++++++\n 3 files changed, 67 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 59a3c37..1f4d954 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--use-path=<path>] <object>\n-'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n+'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]\n \n DESCRIPTION\n -----------\n@@ -20,7 +20,11 @@ object type, or `-s` is used to find the object size, or `--textconv` or\n `--filters` is used (which imply type \"blob\").\n \n In the second form, a list of objects (separated by linefeeds) is provided on\n-stdin, and the SHA-1, type, and size of each object is printed on stdout.\n+stdin, and the SHA-1, type, and size of each object is printed on stdout. The\n+output format can be overridden using the optional `<format>` argument. If\n+either `--textconv` or `--filters` was specified, the input is expected to\n+list the object names followed by the path name, separated by a single white\n+space, so that the appropriate drivers can be determined.\n \n OPTIONS\n -------\n@@ -72,13 +76,17 @@ OPTIONS\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\n-\ton stdin.  May not be combined with any other options or arguments.\n-\tSee the section `BATCH OUTPUT` below for details.\n+\ton stdin.  May not be combined with any other options or arguments\n+\texcept `--textconv` or `--filters`, in which case the input lines\n+\talso need to specify the path, separated by white space.  See the\n+\tsection `BATCH OUTPUT` below for details.\n \n --batch-check::\n --batch-check=<format>::\n \tPrint object information for each object provided on stdin.  May\n-\tnot be combined with any other options or arguments.  See the\n+\tnot be combined with any other options or arguments except\n+\t`--textconv` or `--filters`, in which case the input lines also\n+\tneed to specify the path, separated by white space.  See the\n \tsection `BATCH OUTPUT` below for details.\n \n --batch-all-objects::\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 5ff58b3..5f91cf4 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -17,6 +17,7 @@ struct batch_options {\n \tint print_contents;\n \tint buffer_output;\n \tint all_objects;\n+\tint cmdmode; /* may be 'w' or 'c' for --filters or --textconv */\n \tconst char *format;\n };\n \n@@ -281,7 +282,32 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \tif (data->type == OBJ_BLOB) {\n \t\tif (opt->buffer_output)\n \t\t\tfflush(stdout);\n-\t\tif (stream_blob_to_fd(1, sha1, NULL, 0) < 0)\n+\t\tif (opt->cmdmode) {\n+\t\t\tchar *contents;\n+\t\t\tunsigned long size;\n+\n+\t\t\tif (!data->rest)\n+\t\t\t\tdie(\"missing path for '%s'\", sha1_to_hex(sha1));\n+\n+\t\t\tif (opt->cmdmode == 'w') {\n+\t\t\t\tif (filter_object(data->rest, 0100644, sha1,\n+\t\t\t\t\t\t  &contents, &size))\n+\t\t\t\t\tdie(\"could not convert '%s' %s\",\n+\t\t\t\t\t    sha1_to_hex(sha1), data->rest);\n+\t\t\t} else if (opt->cmdmode == 'c') {\n+\t\t\t\tenum object_type type;\n+\t\t\t\tif (!textconv_object(data->rest, 0100644, sha1,\n+\t\t\t\t\t\t     1, &contents, &size))\n+\t\t\t\t\tcontents = read_sha1_file(sha1, &type,\n+\t\t\t\t\t\t\t\t  &size);\n+\t\t\t\tif (!contents)\n+\t\t\t\t\tdie(\"could not convert '%s' %s\",\n+\t\t\t\t\t    sha1_to_hex(sha1), data->rest);\n+\t\t\t} else\n+\t\t\t\tdie(\"BUG: invalid cmdmode: %c\", opt->cmdmode);\n+\t\t\tbatch_write(opt, contents, size);\n+\t\t\tfree(contents);\n+\t\t} else if (stream_blob_to_fd(1, sha1, NULL, 0) < 0)\n \t\t\tdie(\"unable to stream %s to stdout\", sha1_to_hex(sha1));\n \t}\n \telse {\n@@ -418,6 +444,8 @@ static int batch_objects(struct batch_options *opt)\n \tdata.mark_query = 1;\n \tstrbuf_expand(&buf, opt->format, expand_format, &data);\n \tdata.mark_query = 0;\n+\tif (opt->cmdmode)\n+\t\tdata.split_on_whitespace = 1;\n \n \tif (opt->all_objects) {\n \t\tstruct object_info empty;\n@@ -483,7 +511,7 @@ static int batch_objects(struct batch_options *opt)\n \n static const char * const cat_file_usage[] = {\n \tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--use-path=<path>] <object>\"),\n-\tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n+\tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv|--filters]\"),\n \tNULL\n };\n \n@@ -554,7 +582,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);\n \n \tif (opt) {\n-\t\tif (argc == 1)\n+\t\tif (batch.enabled && (opt == 'c' || opt == 'w'))\n+\t\t\tbatch.cmdmode = opt;\n+\t\telse if (argc == 1)\n \t\t\tobj_name = argv[0];\n \t\telse\n \t\t\tusage_with_options(cat_file_usage, options);\n@@ -566,8 +596,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\t} else\n \t\t\tusage_with_options(cat_file_usage, options);\n \t}\n-\tif (batch.enabled && (opt || argc)) {\n-\t\tusage_with_options(cat_file_usage, options);\n+\tif (batch.enabled) {\n+\t\tif (batch.cmdmode != opt || argc)\n+\t\t\tusage_with_options(cat_file_usage, options);\n+\t\tif (batch.cmdmode && batch.all_objects)\n+\t\t\tdie(\"--batch-all-objects cannot be combined with \"\n+\t\t\t    \"--textconv nor with --filters\");\n \t}\n \n \tif ((batch.follow_symlinks || batch.all_objects) && !batch.enabled) {\n@@ -579,6 +613,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(cat_file_usage, options);\n \t}\n \n+\tif (force_path && batch.enabled) {\n+\t\terror(\"--use-path=<path> incompatible with --batch\");\n+\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\n \tif (batch.buffer_output < 0)\n \t\tbatch.buffer_output = batch.all_objects;\n \ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nindex fd17159..89ae868 100755\n--- a/t/t8010-cat-file-filters.sh\n+++ b/t/t8010-cat-file-filters.sh\n@@ -44,4 +44,14 @@ test_expect_success 'cat-file --textconv --use-path=<path> works' '\n \ttest uryyb = \"$(cat rot13 | remove_cr)\"\n '\n \n+test_expect_success 'cat-file --textconv --batch works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n+\tprintf \"%s hello.txt\\n%s hello\\n\" $sha1 $sha1 |\n+\tgit cat-file --textconv --batch >actual &&\n+\tprintf \"%s blob 6\\nuryyb\\r\\n\\n%s blob 6\\nhello\\n\\n\" \\\n+\t\t$sha1 $sha1 >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.9.2.691.g78954f3\n"},{"id":"299605","messageId":"561560a6144f775fdde3fa51f4acc54867797027.1471524357.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1471524357.git.johannes.schindelin@gmx.de","subject":"[PATCH 1/4] cat-file: fix a grammo in the man page","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-18T12:46:13Z","receivedAt":"2016-08-18T13:03:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\"... has be ...\" -> \"... has to be ...\"\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 18d03d8..071029b 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -54,8 +54,9 @@ OPTIONS\n \n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n-\t<object> has be of the form <tree-ish>:<path>, or :<path> in order\n-\tto apply the filter to the content recorded in the index at <path>.\n+\t<object> has to be of the form <tree-ish>:<path>, or :<path> in\n+\torder to apply the filter to the content recorded in the index at\n+\t<path>.\n \n --batch::\n --batch=<format>::\n-- \n2.9.2.691.g78954f3\n\n\n"},{"id":"299606","messageId":"cover.1471524357.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":null,"subject":"[PATCH 0/4] cat-file: optionally convert to worktree version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-18T12:46:08Z","receivedAt":"2016-08-18T13:03:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When third-party tools need to access to contents of blobs in the\ndatabase, they might be more interested in the worktree version than in\nthe \"clean\" version of said contents.\n\nThis branch introduces the --filters option to make that happen, the\n--use-path option to provide the path separately if the blob name rather\nthan the tree name is availale, and offers batch support in which case\nit expects the object names and the path on its input lines, separated\nby white space.\n\nThe new --filters option is an obvious sibling of --textconv, and shares\nthe peculiar feature that the drivers (and end-of-line convention) are\ndetermined from the current worktree, not from the attributes stored in\nthe revision that may have been part of the object name.\n\nAs --textconv is so similar to --filters, it was taught to understand\nthe --use-path option and it was made compatible with batch mode, too.\n\nI briefly considered teaching the batch mode to extract the path from\nobject names if they are specified as <tree-ish>:<path>. The changes\nwould be quite intrusive, though, and uglify the code substanitially. So\nI decided against that.\n\n\nJohannes Schindelin (4):\n  cat-file: fix a grammo in the man page\n  cat-file: introduce the --filters option\n  cat-file --textconv/--filters: allow specifying the path separately\n  cat-file: support --textconv/--filters in batch mode\n\n Documentation/git-cat-file.txt |  40 ++++++++++++----\n builtin/cat-file.c             | 106 +++++++++++++++++++++++++++++++++++++----\n t/t8010-cat-file-filters.sh    |  57 ++++++++++++++++++++++\n 3 files changed, 185 insertions(+), 18 deletions(-)\n create mode 100755 t/t8010-cat-file-filters.sh\n\nPublished-As: https://github.com/dscho/git/releases/tag/cat-file-filters-v1\nFetch-It-Via: git fetch https://github.com/dscho/git cat-file-filters-v1\n\n-- \n2.9.2.691.g78954f3\n\nbase-commit: d63263a4dee8fc7da9b97bbdedf9c0d1f33024d4\n"},{"id":"299620","messageId":"xmqqfuq26mu3.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"787224ce9a382ddd1180a408e784ca26993e5603.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-18T16:52:52Z","receivedAt":"2016-08-18T19:10:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> There are circumstances when it is relatively easy to figure out the\n> object name for a given path, but not the revision. For example, when\n\nrevision of the containing tree, I presume?\n\n> Let's simplify this dramatically, because we do not really need that\n> revision at all: all we care about is that we know the path. In the\n> scenario described above, we do know the path, and we just want to\n> specify it separately from the object name.\n\nI wouldn't call it \"simplifying dramatically\".  It is just to\nsupport two use cases that is different from the use case where you\nwant to use \"<tree>:<path>\".\n\nWe already have a precedent in \"hash-object --path=<path>\" for these\ntwo different uses cases from the primary one.  That form can be\nused when we know the contents but we do not know where the contents\ncame from.  It can also be used when we want to pretend that\ncontents came from a specific path, that may be different from the\nfile we are hashing.\n\nLet's be consistent and (1) call it \"--path\", and (2) explain it as\na feature to allow you to tell the path separately or allow you to\npretend that the content is at a path different from reality.\n\nAfter all, you would want to ignore <path2> part in this construct:\n\n\tgit cat-file --filter --path=<path1> HEAD:<path2>\n\nfor the purpose of filtering, right?\n\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index 0b74afa..5ff58b3 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -20,6 +20,8 @@ struct batch_options {\n>  \tconst char *format;\n>  };\n>  \n> +static const char *force_path;\n> +\n>  static int filter_object(const char *path, unsigned mode,\n>  \t\t\t const unsigned char *sha1,\n>  \t\t\t char **buf, unsigned long *size)\n> @@ -89,21 +91,24 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \t\treturn !has_sha1_file(sha1);\n>  \n>  \tcase 'w':\n> -\t\tif (!obj_context.path[0])\n> +\t\tif (!force_path && !obj_context.path[0])\n>  \t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n>  \t\t\t    \"<sha1:path>\", obj_name);\n>  \n> -\t\tif (filter_object(obj_context.path, obj_context.mode,\n> +\t\tif (filter_object(force_path ? force_path : obj_context.path,\n> +\t\t\t\t  force_path ? 0100644 : obj_context.mode,\n>  \t\t\t\t  sha1, &buf, &size))\n\nThe mode override is somewhat questionable.  Wouldn't you want to\nreject\n\n\tgit cat-file --filter --path=Makefile HEAD:RelNotes\n\nwhen HEAD:RelNotes blob is known to be a symbolic link?  After all,\nyou would reject this\n\n\tgit cat-file --filter --path=Makefile HEAD:t/\n\nand it is quite similar, no?  I think this can be argued both ways,\nbut I have a feeling that obj_context.mode, if available, should be\nhonored with or without force_path.\n\n> diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\n> index e466634..fd17159 100755\n> --- a/t/t8010-cat-file-filters.sh\n> +++ b/t/t8010-cat-file-filters.sh\n> @@ -31,4 +31,17 @@ test_expect_success 'cat-file --filters converts to worktree version' '\n>  \thas_cr actual\n>  '\n>  \n> +test_expect_success 'cat-file --filters --use-path=<path> works' '\n> +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n> +\tgit cat-file --filters --use-path=world.txt $sha1 >actual &&\n> +\thas_cr actual\n> +'\n> +\n> +test_expect_success 'cat-file --textconv --use-path=<path> works' '\n> +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n> +\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n> +\tgit cat-file --textconv --use-path=hello.txt $sha1 >rot13 &&\n> +\ttest uryyb = \"$(cat rot13 | remove_cr)\"\n> +'\n\nI think I saw some code to ensure \"when giving this option you need\nthat option in effect, too\"; they should be tested here, too, no?\n"},{"id":"299633","messageId":"xmqqoa4p4rua.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"20160818220530.2dcsag4qeitia4ao@sigill.intra.peff.net","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-18T22:47:41Z","receivedAt":"2016-08-19T01:11:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n>\n>> With this patch, --batch can be combined with --textconv or --filters.\n>> For this to work, the input needs to have the form\n>> \n>> \t<object name><single white space><path>\n>> \n>> so that the filters can be chosen appropriately.\n>\n> The object name can have spaces in it, too. E.g.:\n>\n>   HEAD:path with spaces\n>\n> or even:\n>\n>   :/grep for this\n\nWhen I wrote my review, I didn't consider this use case.\n\nThere is no -z format in --batch, which is unfortunate.  If we had\none, it would trivially make it possible to do so, and we can even\nhave paths with LF in them ;-).  On the other hand, producing a NUL\nseparated input is a chore.\n\nPerhaps a new and separate option that is similar to \"--batch\" but\nlacks support for %(rest) and accepts _ONLY_ 40-hex as object name\nis the best we can do, then?\n\n> (as was pointed out to me when I tried to turn on %(rest) handling by\n> default, long ago). How do those work with your patch?\n>\n> It looks like the extra split isn't enabled unless one of those options\n> is selected. Since --filters is new, that's OK for backwards\n> compatibility. But --textconv isn't. So I think:\n>\n>   echo \"HEAD:path with spaces\" |\n>   git cat-file --textconv --batch\n>\n> is regressed by this patch.\n>\n> I wonder if we need an option specifically to say \"the object name can\n> be split\". Right now it kicks in automatically if you use \"%(rest)\" in\n> your format, but you might not care about passing along that output\n> (e.g., a lot of times I am piping \"rev-list\" straight to cat-file, and I\n> have to use a separate \"cut\" to throw away the pathnames).\n>\n> -Peff\n"},{"id":"299634","messageId":"xmqqk2fe6njs.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"f1e188907f31abef9e82bd6b0da120ab7d9bd4a7.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-18T16:37:27Z","receivedAt":"2016-08-19T01:11:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> As suggested by its name, the --filters option applies the filters\n> that are currently configured for the specified path.\n>\n> This feature comes in handy when a 3rd-party tool wants to work with\n> the contents of files from past revisions as if they had been checked\n> out, but without detouring via temporary files.\n>\n> Note that we ensure that symbolic links are unaffected (we know from\n> looking at the mode whether it refers to a symbolic link or a regular\n> file).\n\nI think you can lose the last paragraph and enrich the first one\ninstead.  The text as-given does not even say anything about the new\noption affecting only blobs.\n\n\tThe --filters option applies the convert_to_working_tree()\n\tfilter for the path when showing the contents of a regular\n\tfile blob object.\n\nor something like that.\n\n> +--filters::\n> +\tShow the content as transformed by the filters configured in\n> +\tthe current working tree for the given <path> (i.e. smudge filters,\n> +\tend-of-line conversion, etc). In this case, <object> has to be of\n> +\tthe form <tree-ish>:<path>, or :<path>.\n\nMakes sense.  We show the contents as if we are checking the blob\nout to the given <path>, in other words.\n\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index 2dfe626..0b74afa 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -20,6 +20,33 @@ struct batch_options {\n>  \tconst char *format;\n>  };\n>  \n> +static int filter_object(const char *path, unsigned mode,\n> +\t\t\t const unsigned char *sha1,\n> +\t\t\t char **buf, unsigned long *size)\n> +{\n> +\tenum object_type type;\n> +\n> +\t*buf = read_sha1_file(sha1, &type, size);\n> +\tif (!*buf)\n> +\t\treturn error(_(\"cannot read object %s '%s'\"),\n> +\t\t\tsha1_to_hex(sha1), path);\n> +\tif (type != OBJ_BLOB) {\n> +\t\tfree(*buf);\n> +\t\treturn error(_(\"blob expected for %s '%s'\"),\n> +\t\t\tsha1_to_hex(sha1), path);\n> +\t}\n> +\tif (S_ISREG(mode)) {\n> +\t\tstruct strbuf strbuf = STRBUF_INIT;\n> +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n> +\t\t\tfree(*buf);\n> +\t\t\t*size = strbuf.len;\n> +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n> +\t\t}\n> +\t}\n\nThis is just a tangent for future clean-up of the coding convention,\nbut if we used size_t internally throughout the system, we would be\nable to use strbuf_detach(&strbuf, size) instead.  With the current\ncoding convention, all internal sizes are ulong, and this is the\nbest we could do.\n\n> @@ -61,6 +88,16 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \tcase 'e':\n>  \t\treturn !has_sha1_file(sha1);\n>  \n> +\tcase 'w':\n> +\t\tif (!obj_context.path[0])\n> +\t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n> +\t\t\t    \"<sha1:path>\", obj_name);\n> +\n> +\t\tif (filter_object(obj_context.path, obj_context.mode,\n> +\t\t\t\t  sha1, &buf, &size))\n> +\t\t\treturn -1;\n> +\t\tbreak;\n> +\n\nMakes sense.\n\n> diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\n> new file mode 100755\n> index 0000000..e466634\n> --- /dev/null\n> +++ b/t/t8010-cat-file-filters.sh\n> @@ -0,0 +1,34 @@\n> +#!/bin/sh\n> +\n> +test_description='git cat-file filters support'\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup ' '\n> +\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n> +\techo \"hello\" | append_cr >world.txt &&\n> +\tgit add .gitattributes world.txt &&\n> +\ttest_tick &&\n> +\tgit commit -m \"Initial commit\"\n> +'\n\nOK, so we ask *.txt in the working tree to be CRLF (and presumably\nthat means the in-repository objects are LF).\n\n> +has_cr () {\n> +\ttr '\\015' Q <\"$1\" | grep Q >/dev/null\n> +}\n> +\n> +test_expect_success 'no filters with `git show`' '\n> +\tgit show HEAD:world.txt >actual &&\n> +\t! has_cr actual\n> +\n> +'\n> +\n> +test_expect_success 'no filters with cat-file' '\n> +\tgit cat-file blob HEAD:world.txt >actual &&\n> +\t! has_cr actual\n> +'\n\nOK.\n\n> +test_expect_success 'cat-file --filters converts to worktree version' '\n> +\tgit cat-file --filters HEAD:world.txt >actual &&\n> +\thas_cr actual\n> +'\n\nOK.\n"},{"id":"299635","messageId":"xmqqoa4q6ob5.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"561560a6144f775fdde3fa51f4acc54867797027.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 1/4] cat-file: fix a grammo in the man page","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-18T16:21:02Z","receivedAt":"2016-08-19T01:11:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> \"... has be ...\" -> \"... has to be ...\"\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  Documentation/git-cat-file.txt | 5 +++--\n>  1 file changed, 3 insertions(+), 2 deletions(-)\n>\n> diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\n> index 18d03d8..071029b 100644\n> --- a/Documentation/git-cat-file.txt\n> +++ b/Documentation/git-cat-file.txt\n> @@ -54,8 +54,9 @@ OPTIONS\n>  \n>  --textconv::\n>  \tShow the content as transformed by a textconv filter. In this case,\n> -\t<object> has be of the form <tree-ish>:<path>, or :<path> in order\n> -\tto apply the filter to the content recorded in the index at <path>.\n> +\t<object> has to be of the form <tree-ish>:<path>, or :<path> in\n> +\torder to apply the filter to the content recorded in the index at\n> +\t<path>.\n\nThanks.  That's an ancient typo dating back to 2010 ;-)\n\n\n"},{"id":"299640","messageId":"xmqqbn0q6m4v.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"2315ae5ab6918a7c1567f11a64093a860983bc20.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-18T17:08:00Z","receivedAt":"2016-08-19T01:14:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> With this patch, --batch can be combined with --textconv or --filters.\n> For this to work, the input needs to have the form\n>\n> \t<object name><single white space><path>\n>\n> so that the filters can be chosen appropriately.\n>  --batch::\n>  --batch=<format>::\n>  \tPrint object information and contents for each object provided\n> -\ton stdin.  May not be combined with any other options or arguments.\n> -\tSee the section `BATCH OUTPUT` below for details.\n> +\ton stdin.  May not be combined with any other options or arguments\n> +\texcept `--textconv` or `--filters`, in which case the input lines\n> +\talso need to specify the path, separated by white space.  See the\n> +\tsection `BATCH OUTPUT` below for details.\n\nMakes sense.  This format still allows\n\n\tHEAD:<path2> <path1>\n\ni.e. the object name is taken from path2 but we forget it and\npretend that the blob sits at path2, which is a good feature.\n\nIf I am not mistaken, your cover letter alluded that it might be\nideal to take \"HEAD:<path>\" (nothing else) as input, grab \"<path>\"\nand feed that to the filtering machinery, but you decided to stop\nshort of doing that.  I actually think that it is the right thing to\ndo for this feature to ignore the trailing :<path> in the object\nname, iow, I agree with the result from the feature design POV.\n\nThe only thing that somewhat is worrysome is what would happen to\n%(rest).  I guess [*1*] it is OK to declare that you cannot use %(rest) in\nyour output format when --filter/--textconv is in use, but if that\nis the direction we are going, that limitation needs to be\ndocumented.\n\n\n[Footnote]\n\n*1* This is just a \"guess\", because I do not know what people are\nusing %(rest) for.  It is plausible that their use case do not need\n--filter/--textconv at all, and if that is the case, having this\nlimitation is perfectly fine.\n"},{"id":"299659","messageId":"20160818154908.GB17141@tb-raspi","threadId":"43877","inReplyTo":"f1e188907f31abef9e82bd6b0da120ab7d9bd4a7.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-08-18T15:49:08Z","receivedAt":"2016-08-19T01:52:05Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On Thu, Aug 18, 2016 at 02:46:17PM +0200, Johannes Schindelin wrote:\n> As suggested by its name, the --filters option applies the filters\n\n[]\n> diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nDoes it make sense to integrate tests into t1006-cat-file ?\n> new file mode 100755\n> index 0000000..e466634\n> --- /dev/null\n> +++ b/t/t8010-cat-file-filters.sh\n> @@ -0,0 +1,34 @@\n> +#!/bin/sh\n> +\n> +test_description='git cat-file filters support'\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup ' '\n> +\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n> +\techo \"hello\" | append_cr >world.txt &&\n> +\tgit add .gitattributes world.txt &&\n> +\ttest_tick &&\n> +\tgit commit -m \"Initial commit\"\n> +'\n> +\n> +has_cr () {\n> +\ttr '\\015' Q <\"$1\" | grep Q >/dev/null\n> +}\n> +\n> +test_expect_success 'no filters with `git show`' '\n> +\tgit show HEAD:world.txt >actual &&\nI would prefer to have something using\n  cat >expect <<-\\EOF &&\n  xxx\n  test_cmp expect actual\nto make it easier to debug in case of a failure ?\n"},{"id":"299668","messageId":"20160818220530.2dcsag4qeitia4ao@sigill.intra.peff.net","threadId":"43877","inReplyTo":"2315ae5ab6918a7c1567f11a64093a860983bc20.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-08-18T22:05:31Z","receivedAt":"2016-08-19T02:05:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n\n> With this patch, --batch can be combined with --textconv or --filters.\n> For this to work, the input needs to have the form\n> \n> \t<object name><single white space><path>\n> \n> so that the filters can be chosen appropriately.\n\nThe object name can have spaces in it, too. E.g.:\n\n  HEAD:path with spaces\n\nor even:\n\n  :/grep for this\n\n(as was pointed out to me when I tried to turn on %(rest) handling by\ndefault, long ago). How do those work with your patch?\n\nIt looks like the extra split isn't enabled unless one of those options\nis selected. Since --filters is new, that's OK for backwards\ncompatibility. But --textconv isn't. So I think:\n\n  echo \"HEAD:path with spaces\" |\n  git cat-file --textconv --batch\n\nis regressed by this patch.\n\nI wonder if we need an option specifically to say \"the object name can\nbe split\". Right now it kicks in automatically if you use \"%(rest)\" in\nyour format, but you might not care about passing along that output\n(e.g., a lot of times I am piping \"rev-list\" straight to cat-file, and I\nhave to use a separate \"cut\" to throw away the pathnames).\n\n-Peff\n"},{"id":"299669","messageId":"20160818154213.GA17141@tb-raspi","threadId":"43877","inReplyTo":"2315ae5ab6918a7c1567f11a64093a860983bc20.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-08-18T15:42:13Z","receivedAt":"2016-08-19T02:12:30Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n> With this patch, --batch can be combined with --textconv or --filters.\n> For this to work, the input needs to have the form\n> \n> \t<object name><single white space><path>\n> \n> so that the filters can be chosen appropriately.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  Documentation/git-cat-file.txt | 18 +++++++++++-----\n>  builtin/cat-file.c             | 49 +++++++++++++++++++++++++++++++++++++-----\n>  t/t8010-cat-file-filters.sh    | 10 +++++++++\n>  3 files changed, 67 insertions(+), 10 deletions(-)\n> \n> diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\n> index 59a3c37..1f4d954 100644\n> --- a/Documentation/git-cat-file.txt\n> +++ b/Documentation/git-cat-file.txt\n> @@ -10,7 +10,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--use-path=<path>] <object>\n> -'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n> +'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]\n>  \n>  DESCRIPTION\n>  -----------\n> @@ -20,7 +20,11 @@ object type, or `-s` is used to find the object size, or `--textconv` or\n>  `--filters` is used (which imply type \"blob\").\n>  \n>  In the second form, a list of objects (separated by linefeeds) is provided on\n> -stdin, and the SHA-1, type, and size of each object is printed on stdout.\n> +stdin, and the SHA-1, type, and size of each object is printed on stdout. The\n> +output format can be overridden using the optional `<format>` argument. If\n> +either `--textconv` or `--filters` was specified, the input is expected to\n> +list the object names followed by the path name, separated by a single white\n> +space, so that the appropriate drivers can be determined.\n>  \n>  OPTIONS\n>  -------\n> @@ -72,13 +76,17 @@ OPTIONS\n>  --batch::\n>  --batch=<format>::\n>  \tPrint object information and contents for each object provided\n> -\ton stdin.  May not be combined with any other options or arguments.\n> -\tSee the section `BATCH OUTPUT` below for details.\n> +\ton stdin.  May not be combined with any other options or arguments\n> +\texcept `--textconv` or `--filters`, in which case the input lines\n> +\talso need to specify the path, separated by white space.  See the\n> +\tsection `BATCH OUTPUT` below for details.\n>  \n>  --batch-check::\n>  --batch-check=<format>::\n>  \tPrint object information for each object provided on stdin.  May\n> -\tnot be combined with any other options or arguments.  See the\n> +\tnot be combined with any other options or arguments except\n> +\t`--textconv` or `--filters`, in which case the input lines also\n> +\tneed to specify the path, separated by white space.  See the\n>  \tsection `BATCH OUTPUT` below for details.\n>  \n>  --batch-all-objects::\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index 5ff58b3..5f91cf4 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -17,6 +17,7 @@ struct batch_options {\n>  \tint print_contents;\n>  \tint buffer_output;\n>  \tint all_objects;\n> +\tint cmdmode; /* may be 'w' or 'c' for --filters or --textconv */\nHow do I read 'w' and 'c' ?\nwilter and cextconv ? Does it make sense to use an enum here ?\nOr a #define ?\n\n"},{"id":"299689","messageId":"20160819085700.GA23254@tb-raspi","threadId":"43877","inReplyTo":"f1e188907f31abef9e82bd6b0da120ab7d9bd4a7.1471524357.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-08-19T08:57:00Z","receivedAt":"2016-08-19T08:57:25Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"[]\nOn Thu, Aug 18, 2016 at 02:46:17PM +0200, Johannes Schindelin wrote:\n\n> diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\n> index 071029b..7d48735 100644\n> --- a/Documentation/git-cat-file.txt\n> +++ b/Documentation/git-cat-file.txt\n> @@ -9,15 +9,15 @@ git-cat-file - Provide content or type and size information for repository objec\n>  SYNOPSIS\n>  --------\n>  [verse]\n> -'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv ) <object>\n> +'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n>  'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n>  \n>  DESCRIPTION\n>  -----------\n>  In its first form, the command provides the content or the type of an object in\n>  the repository. The type is required unless `-t` or `-p` is used to find the\n> -object type, or `-s` is used to find the object size, or `--textconv` is used\n> -(which implies type \"blob\").\n> +object type, or `-s` is used to find the object size, or `--textconv` or\n> +`--filters` is used (which imply type \"blob\").\n>  \n>  In the second form, a list of objects (separated by linefeeds) is provided on\n>  stdin, and the SHA-1, type, and size of each object is printed on stdout.\n> @@ -58,6 +58,12 @@ OPTIONS\n>  \torder to apply the filter to the content recorded in the index at\n>  \t<path>.\n>  \n> +--filters::\n> +\tShow the content as transformed by the filters configured in\nMinor comment:\ns/transformed/converted/ ?\n\nDoes it make sense to be more specific here:\nThe order of conversion is\n- ident\n- CRLF\n- smudge\n"},{"id":"299692","messageId":"alpine.DEB.2.20.1608191423440.4924@virtualbox","threadId":"43877","inReplyTo":"20160818154213.GA17141@tb-raspi","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T12:25:51Z","receivedAt":"2016-08-19T12:26:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Torsten,\n\nOn Thu, 18 Aug 2016, Torsten Bögershausen wrote:\n\n> On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n> > diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> > index 5ff58b3..5f91cf4 100644\n> > --- a/builtin/cat-file.c\n> > +++ b/builtin/cat-file.c\n> > @@ -17,6 +17,7 @@ struct batch_options {\n> >  \tint print_contents;\n> >  \tint buffer_output;\n> >  \tint all_objects;\n> > +\tint cmdmode; /* may be 'w' or 'c' for --filters or --textconv */\n> How do I read 'w' and 'c' ?\n> wilter and cextconv ? Does it make sense to use an enum here ?\n> Or a #define ?\n\nSorry, Torsten, this is not my doing. So I cannot explain why it is not an\nenum.\n\nI *guess* the rationale for 'c' being the cmdmode of --textconv is \"c for\nconvert\". That is why I chose \"w as in worktree\" as new cmdmode.\n\nCiao,\nDscho"},{"id":"299693","messageId":"alpine.DEB.2.20.1608191426470.4924@virtualbox","threadId":"43877","inReplyTo":"20160818154908.GB17141@tb-raspi","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T12:37:43Z","receivedAt":"2016-08-19T12:37:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Torsten,\n\nOn Thu, 18 Aug 2016, Torsten Bögershausen wrote:\n\n> On Thu, Aug 18, 2016 at 02:46:17PM +0200, Johannes Schindelin wrote:\n> > As suggested by its name, the --filters option applies the filters\n> \n> []\n> > diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\n>\n> Does it make sense to integrate tests into t1006-cat-file ?\n\nt1006 is already a 500+ line script, running 110 cases in 13 seconds over\nhere. I really rather have a new, small, concise and parallelizable\nscript.\n\n> > +test_expect_success 'no filters with `git show`' '\n> > +\tgit show HEAD:world.txt >actual &&\n>\n> I would prefer to have something using\n>   cat >expect <<-\\EOF &&\n>   xxx\n>   test_cmp expect actual\n> to make it easier to debug in case of a failure ?\n\nActually, I find it much harder to debug these \"the output must match\nthese precise bytes, else we fail\" type of test cases. Instead, I describe\nin a natural way what is expected:\n\n\t! has_cr actual\n\nNow, when the test fails, whoever is that poor soul tasked with debugging\nand fixing the breakage knows *what* goes wrong, conceptually.\n\nSo I do not think it would be a good idea to change the test in the way\nyou requested.\n\nAnd now I have a request of my own. When you quote parts of my mail, you\ninsert your answers without surrounding them by empty lines. That makes it\nextraordinarily hard for me to read your mails (in fact, I almost missed\nyour second comment).\n\nCould you please start surrounding your replies by empty lines?\n\nThank you,\nDscho"},{"id":"299694","messageId":"alpine.DEB.2.20.1608191446550.4924@virtualbox","threadId":"43877","inReplyTo":"xmqqk2fe6njs.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T12:49:39Z","receivedAt":"2016-08-19T12:49:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 18 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > As suggested by its name, the --filters option applies the filters\n> > that are currently configured for the specified path.\n> >\n> > [...]\n> \n> I think you can lose the last paragraph and enrich the first one\n> instead.  The text as-given does not even say anything about the new\n> option affecting only blobs.\n> \n> \tThe --filters option applies the convert_to_working_tree()\n> \tfilter for the path when showing the contents of a regular\n> \tfile blob object.\n> \n> or something like that.\n\nDone.\n\nThanks,\nDscho\n"},{"id":"299695","messageId":"alpine.DEB.2.20.1608191450500.4924@virtualbox","threadId":"43877","inReplyTo":"xmqqbn0q6m4v.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T12:59:32Z","receivedAt":"2016-08-19T13:06:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 18 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > With this patch, --batch can be combined with --textconv or --filters.\n> > For this to work, the input needs to have the form\n> >\n> > \t<object name><single white space><path>\n> >\n> > so that the filters can be chosen appropriately.\n> >  --batch::\n> >  --batch=<format>::\n> >  \tPrint object information and contents for each object provided\n> > -\ton stdin.  May not be combined with any other options or arguments.\n> > -\tSee the section `BATCH OUTPUT` below for details.\n> > +\ton stdin.  May not be combined with any other options or arguments\n> > +\texcept `--textconv` or `--filters`, in which case the input lines\n> > +\talso need to specify the path, separated by white space.  See the\n> > +\tsection `BATCH OUTPUT` below for details.\n> \n> Makes sense.  This format still allows\n> \n> \tHEAD:<path2> <path1>\n> \n> i.e. the object name is taken from path2 but we forget it and\n> pretend that the blob sits at path2, which is a good feature.\n\nCorrect.\n\n> If I am not mistaken, your cover letter alluded that it might be\n> ideal to take \"HEAD:<path>\" (nothing else) as input, grab \"<path>\"\n> and feed that to the filtering machinery, but you decided to stop\n> short of doing that.  I actually think that it is the right thing to\n> do for this feature to ignore the trailing :<path> in the object\n> name, iow, I agree with the result from the feature design POV.\n\nI actually decided against it only because it would uglify the code. From\na user point of view, I am a bit annoyed having to say\n\n\t:README README\n\t:Makefile Makefile\n\t:main.c main.c\n\t[...]\n\n> The only thing that somewhat is worrysome is what would happen to\n> %(rest).\n\nWhat would happen is that it would print out the path, as it is exactly\nthat \"rest\" field that is used in the implementation, piggybacking on that\nvery nice feature.\n\nOf course, this means that you simply cannot send \"SHA-1 path rest\" to\ncat-file --batch and expect that to work. Should anybody need that in the\nfuture, they can give it a try themselves to patch cat-file.\n\nCiao,\nDscho\n"},{"id":"299696","messageId":"alpine.DEB.2.20.1608191500470.4924@virtualbox","threadId":"43877","inReplyTo":"20160818220530.2dcsag4qeitia4ao@sigill.intra.peff.net","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T13:09:19Z","receivedAt":"2016-08-19T13:09:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Peff,\n\nOn Thu, 18 Aug 2016, Jeff King wrote:\n\n> On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n> \n> > With this patch, --batch can be combined with --textconv or --filters.\n> > For this to work, the input needs to have the form\n> > \n> > \t<object name><single white space><path>\n> > \n> > so that the filters can be chosen appropriately.\n> \n> The object name can have spaces in it, too. E.g.:\n> \n>   HEAD:path with spaces\n> \n> or even:\n> \n>   :/grep for this\n> \n> (as was pointed out to me when I tried to turn on %(rest) handling by\n> default, long ago). How do those work with your patch?\n\nThey don't ;-)\n\nAnd quite frankly, the documentation should make it clear to users that\nbatch mode with --filters or --textconv won't work when the object name\ncontains white space: it says that the object name is split from the path\nat the first white space character.\n\n> It looks like the extra split isn't enabled unless one of those options\n> is selected. Since --filters is new, that's OK for backwards\n> compatibility. But --textconv isn't.\n\nExcept that it is okay, because --textconv *was not even supported in\nbatch mode*. So there is no backwards compatibility that could be broken.\n\n> I wonder if we need an option specifically to say \"the object name can\n> be split\". Right now it kicks in automatically if you use \"%(rest)\" in\n> your format, but you might not care about passing along that output\n> (e.g., a lot of times I am piping \"rev-list\" straight to cat-file, and I\n> have to use a separate \"cut\" to throw away the pathnames).\n\nAs I said elsewhere in this thread: if anybody encounters that problem,\nthey are welcome to fix it themselves.\n\nMy patch series purpose is to introduce --filters and make it compatible\nwith the batch mode. As I imitated --textconv, it was both easy and\ncorrect to make it compatible with the batch mode, too. But that is the\nextent of this here patch series.\n\nFixing %(rest) for object names containing spaces is distinctly outside\nthe original intent, and certainly outside of my use case.\n\nCiao,\nDscho\n"},{"id":"299697","messageId":"alpine.DEB.2.20.1608191510060.4924@virtualbox","threadId":"43877","inReplyTo":"xmqqoa4p4rua.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T13:11:34Z","receivedAt":"2016-08-19T13:14:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 18 Aug 2016, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n> >\n> >> With this patch, --batch can be combined with --textconv or --filters.\n> >> For this to work, the input needs to have the form\n> >> \n> >> \t<object name><single white space><path>\n> >> \n> >> so that the filters can be chosen appropriately.\n> >\n> > The object name can have spaces in it, too. E.g.:\n> >\n> >   HEAD:path with spaces\n> >\n> > or even:\n> >\n> >   :/grep for this\n> \n> When I wrote my review, I didn't consider this use case.\n> \n> There is no -z format in --batch, which is unfortunate.  If we had\n> one, it would trivially make it possible to do so, and we can even\n> have paths with LF in them ;-).  On the other hand, producing a NUL\n> separated input is a chore.\n\nI think it would make for a fine little project to add support for --batch\n-z.\n\nJust not in this here patch series.\n\nCiao,\nDscho\n"},{"id":"299698","messageId":"20160819132213.njhymlc5diigonlj@sigill.intra.peff.net","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191500470.4924@virtualbox","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-08-19T13:22:14Z","receivedAt":"2016-08-19T13:22:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 19, 2016 at 03:09:19PM +0200, Johannes Schindelin wrote:\n\n> > The object name can have spaces in it, too. E.g.:\n> > \n> >   HEAD:path with spaces\n> > \n> > or even:\n> > \n> >   :/grep for this\n> > \n> > (as was pointed out to me when I tried to turn on %(rest) handling by\n> > default, long ago). How do those work with your patch?\n> \n> They don't ;-)\n> \n> And quite frankly, the documentation should make it clear to users that\n> batch mode with --filters or --textconv won't work when the object name\n> contains white space: it says that the object name is split from the path\n> at the first white space character.\n\nI think that is an obvious implication of the new documentation. I was\njust concerned with a regression from the previous behavior.\n\n> > It looks like the extra split isn't enabled unless one of those options\n> > is selected. Since --filters is new, that's OK for backwards\n> > compatibility. But --textconv isn't.\n> \n> Except that it is okay, because --textconv *was not even supported in\n> batch mode*. So there is no backwards compatibility that could be broken.\n\nAh, OK. I thought we handled \"HEAD:path with spaces\" there, but I see\nthat you cannot even specify \"--textconv\" with \"--batch\", because it\ncomplains of the cmdmode.\n\nSo the new rule becomes \"we split if we see %(rest), or --textconv, or\n--filter\", which is reasonable.\n\n> Fixing %(rest) for object names containing spaces is distinctly outside\n> the original intent, and certainly outside of my use case.\n\nYeah, I agree it is not necessary for this series (I was only\nconsidering it as an option to fix the regression I now see doesn't\nexist).\n\n-Peff\n"},{"id":"299703","messageId":"20160819144422.kkbskkthozfwfezp@sigill.intra.peff.net","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191450500.4924@virtualbox","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-08-19T14:44:22Z","receivedAt":"2016-08-19T14:44:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 19, 2016 at 02:59:32PM +0200, Johannes Schindelin wrote:\n\n> > The only thing that somewhat is worrysome is what would happen to\n> > %(rest).\n> \n> What would happen is that it would print out the path, as it is exactly\n> that \"rest\" field that is used in the implementation, piggybacking on that\n> very nice feature.\n\nGood, that is what I would expect to happen.\n\n> Of course, this means that you simply cannot send \"SHA-1 path rest\" to\n> cat-file --batch and expect that to work. Should anybody need that in the\n> future, they can give it a try themselves to patch cat-file.\n\nRight. The real motivation for %(rest) was to accept \"git rev-list\n--objects\" format, so you can do stuff like:\n\n  git rev-list --objects --all |\n  git cat-file --batch-check='%(objectsize) %(rest)' |\n  sort -rn |\n  head\n\nto get the paths of the largest objects. So the fact that \"%(rest)\" will\nbe the filename in this case is almost certainly the most useful default\n(and if somebody really wants something else, they can try to figure out\nother semantics later).\n\n-Peff\n"},{"id":"299704","messageId":"alpine.DEB.2.20.1608191521410.4924@virtualbox","threadId":"43877","inReplyTo":"xmqqfuq26mu3.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T14:49:23Z","receivedAt":"2016-08-19T14:49:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 18 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > There are circumstances when it is relatively easy to figure out the\n> > object name for a given path, but not the revision. For example, when\n> \n> revision of the containing tree, I presume?\n\nname of containing tree, actually.\n\n> > Let's simplify this dramatically, because we do not really need that\n> > revision at all: all we care about is that we know the path. In the\n> > scenario described above, we do know the path, and we just want to\n> > specify it separately from the object name.\n> \n> I wouldn't call it \"simplifying dramatically\".  It is just to\n> support two use cases that is different from the use case where you\n> want to use \"<tree>:<path>\".\n\n\"this\" was not the code in question. \"this\" is the use case. Just put my\nshoes on for a moment. As described: you have a list of object names and\ntheir path. Now you need to use the --textconv or --filters option, but\nyou do not have the commit name. What do you do? Concoct a script that\ngoes through `git rev-list --all -- <path>` in the hopes of finding a\nrevision soon? I hope after this little exercise you agree that\nintroducing the --path=<path> option simplifies this use case\ndramatically.\n\n> We already have a precedent in \"hash-object --path=<path>\" for these\n> two different uses cases from the primary one.  That form can be\n> used when we know the contents but we do not know where the contents\n> came from.  It can also be used when we want to pretend that\n> contents came from a specific path, that may be different from the\n> file we are hashing.\n\nAgreed. I was unaware of hash-object's existing option.\n\n> Let's be consistent and (1) call it \"--path\", and (2) explain it as\n> a feature to allow you to tell the path separately or allow you to\n> pretend that the content is at a path different from reality.\n> \n> After all, you would want to ignore <path2> part in this construct:\n> \n> \tgit cat-file --filter --path=<path1> HEAD:<path2>\n> \n> for the purpose of filtering, right?\n\nTrue, and I even make use of that in the test for the batch mode.\n\n> > diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> > index 0b74afa..5ff58b3 100644\n> > --- a/builtin/cat-file.c\n> > +++ b/builtin/cat-file.c\n> > @@ -20,6 +20,8 @@ struct batch_options {\n> >  \tconst char *format;\n> >  };\n> >  \n> > +static const char *force_path;\n> > +\n> >  static int filter_object(const char *path, unsigned mode,\n> >  \t\t\t const unsigned char *sha1,\n> >  \t\t\t char **buf, unsigned long *size)\n> > @@ -89,21 +91,24 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n> >  \t\treturn !has_sha1_file(sha1);\n> >  \n> >  \tcase 'w':\n> > -\t\tif (!obj_context.path[0])\n> > +\t\tif (!force_path && !obj_context.path[0])\n> >  \t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n> >  \t\t\t    \"<sha1:path>\", obj_name);\n> >  \n> > -\t\tif (filter_object(obj_context.path, obj_context.mode,\n> > +\t\tif (filter_object(force_path ? force_path : obj_context.path,\n> > +\t\t\t\t  force_path ? 0100644 : obj_context.mode,\n> >  \t\t\t\t  sha1, &buf, &size))\n> \n> The mode override is somewhat questionable.  Wouldn't you want to\n> reject\n> \n> \tgit cat-file --filter --path=Makefile HEAD:RelNotes\n> \n> when HEAD:RelNotes blob is known to be a symbolic link?  After all,\n> you would reject this\n> \n> \tgit cat-file --filter --path=Makefile HEAD:t/\n> \n> and it is quite similar, no?  I think this can be argued both ways,\n> but I have a feeling that obj_context.mode, if available, should be\n> honored with or without force_path.\n\nI see your point. All I wanted to do was to enable\n\n\tgit cat-file --filters --path=Makefile cafebabe\n\nin which case obj_context.mode == S_IFINVALID. I fixed it (see interdiff\nof the next iteration).\n\n> > diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\n> > index e466634..fd17159 100755\n> > --- a/t/t8010-cat-file-filters.sh\n> > +++ b/t/t8010-cat-file-filters.sh\n> > @@ -31,4 +31,17 @@ test_expect_success 'cat-file --filters converts to worktree version' '\n> >  \thas_cr actual\n> >  '\n> >  \n> > +test_expect_success 'cat-file --filters --use-path=<path> works' '\n> > +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n> > +\tgit cat-file --filters --use-path=world.txt $sha1 >actual &&\n> > +\thas_cr actual\n> > +'\n> > +\n> > +test_expect_success 'cat-file --textconv --use-path=<path> works' '\n> > +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n> > +\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n> > +\tgit cat-file --textconv --use-path=hello.txt $sha1 >rot13 &&\n> > +\ttest uryyb = \"$(cat rot13 | remove_cr)\"\n> > +'\n> \n> I think I saw some code to ensure \"when giving this option you need\n> that option in effect, too\"; they should be tested here, too, no?\n\nNo, I would rather not test for that. These conditionals are purely for\nany user's convenience, in case they specify an option that has no effect.\nThey are absolutely not essential for the function introduced in this\npatch series.\n\nCiao,\nDscho\n\n"},{"id":"299706","messageId":"alpine.DEB.2.20.1608191656080.4924@virtualbox","threadId":"43877","inReplyTo":"20160819085700.GA23254@tb-raspi","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-19T15:00:20Z","receivedAt":"2016-08-19T15:00:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Torsten,\n\nOn Fri, 19 Aug 2016, Torsten Bögershausen wrote:\n\n> On Thu, Aug 18, 2016 at 02:46:17PM +0200, Johannes Schindelin wrote:\n> \n> > +--filters::\n> > +\tShow the content as transformed by the filters configured in\n>\n> Minor comment:\n> s/transformed/converted/ ?\n\nSure.\n\n> Does it make sense to be more specific here:\n> The order of conversion is\n> - ident\n> - CRLF\n> - smudge\n\nI do not think it makes sense to complexify the documentation in that\nmanner. The filters should always be applied in the same order, methinks,\nand it would only clutter the man page to repeat that order here.\n\nCiao,\nDscho"},{"id":"299708","messageId":"20160819150632.wa4wvidzqmrrkcfs@sigill.intra.peff.net","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191423440.4924@virtualbox","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-08-19T15:06:32Z","receivedAt":"2016-08-19T15:06:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 19, 2016 at 02:25:51PM +0200, Johannes Schindelin wrote:\n\n> > On Thu, Aug 18, 2016 at 02:46:28PM +0200, Johannes Schindelin wrote:\n> > > diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> > > index 5ff58b3..5f91cf4 100644\n> > > --- a/builtin/cat-file.c\n> > > +++ b/builtin/cat-file.c\n> > > @@ -17,6 +17,7 @@ struct batch_options {\n> > >  \tint print_contents;\n> > >  \tint buffer_output;\n> > >  \tint all_objects;\n> > > +\tint cmdmode; /* may be 'w' or 'c' for --filters or --textconv */\n> > How do I read 'w' and 'c' ?\n> > wilter and cextconv ? Does it make sense to use an enum here ?\n> > Or a #define ?\n> \n> Sorry, Torsten, this is not my doing. So I cannot explain why it is not an\n> enum.\n> \n> I *guess* the rationale for 'c' being the cmdmode of --textconv is \"c for\n> convert\". That is why I chose \"w as in worktree\" as new cmdmode.\n\nI think it started as a 'char' because it was representing the\nsingle-letter options of \"cat-file -e\", \"cat-file -s\", etc. And then the\ntextconv patches started the monstrosity of \"c\".\n\nI don't think cleaning it up needs to be part of your series, but it\nmight be nice low-hanging fruit for somebody to clean up on top.\n\n-Peff\n"},{"id":"299714","messageId":"xmqq7fbc4ubk.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191426470.4924@virtualbox","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-19T16:06:23Z","receivedAt":"2016-08-19T16:06:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Actually, I find it much harder to debug these \"the output must match\n> these precise bytes, else we fail\" type of test cases. Instead, I describe\n> in a natural way what is expected:\n>\n> \t! has_cr actual\n>\n> Now, when the test fails, whoever is that poor soul tasked with debugging\n> and fixing the breakage knows *what* goes wrong, conceptually.\n\nI am of two minds but 60% in favor of the \"We only care about\npresense of CR\" approach.  Of course, the remaining 40% is \"other\npeople may break the code in such a way that still has CR at the end\nof the line but change ealier bytes on the line in the future (an\nobvious way to do so is to turn an input \"ABC\\n\" into \"AB\\r\\n\"), and\nwe would want to catch it\".  But the conversion machinery is tested\nelsewhere in the test suite, and this test is more about the cat-file\ncommand making a call into the conversion machinery when and only\nwhen it is necessary, so that sways me towards \"has_cr is what we\nwant here\".\n\n> Could you please start surrounding your replies by empty lines?\n\nGood suggestion.  I have exactly the same problem whenever I read\nmessages without blanks at paragraph boundaries.\n\nThanks.\n"},{"id":"299715","messageId":"xmqq37m04uan.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191656080.4924@virtualbox","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-19T16:06:56Z","receivedAt":"2016-08-19T16:07:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Does it make sense to be more specific here:\n>> The order of conversion is\n>> - ident\n>> - CRLF\n>> - smudge\n>\n> I do not think it makes sense to complexify the documentation in that\n> manner.\n\nRight.\n"},{"id":"299716","messageId":"xmqqy43s3fin.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191521410.4924@virtualbox","subject":"Re: [PATCH 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-19T16:11:28Z","receivedAt":"2016-08-19T16:12:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I think I saw some code to ensure \"when giving this option you need\n>> that option in effect, too\"; they should be tested here, too, no?\n>\n> No, I would rather not test for that. These conditionals are purely for\n> any user's convenience, in case they specify an option that has no effect.\n> They are absolutely not essential for the function introduced in this\n> patch series.\n\nI didn't say \"you would want to test these, no?\", did I?\n\nI do not want to see bugreports that say \"I wanted to use this new\nfeature and by mistake gave only --path without giving --filter; Git\nshould have complained.  I found a bug, hooray!\" when somebody in\nthe future refactors the command line option parsing and breaks the\ncheck you already have.\n\n"},{"id":"299717","messageId":"xmqqtweg3f4s.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"20160819150632.wa4wvidzqmrrkcfs@sigill.intra.peff.net","subject":"Re: [PATCH 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-19T16:19:47Z","receivedAt":"2016-08-19T16:19:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>> Sorry, Torsten, this is not my doing. So I cannot explain why it is not an\n>> enum.\n>> \n>> I *guess* the rationale for 'c' being the cmdmode of --textconv is \"c for\n>> convert\". That is why I chose \"w as in worktree\" as new cmdmode.\n>\n> I think it started as a 'char' because it was representing the\n> single-letter options of \"cat-file -e\", \"cat-file -s\", etc. And then the\n> textconv patches started the monstrosity of \"c\".\n\nI think it was merely 't' was taken for \"-t\" (one beauty of using\nthe OPT_CMDMODE for options with shorthand is that we do not need\nany enum, as the short-form options already form an enum), so\n\"textConv\" was the compromise.  It could have been 'T' or even \\C-t\n;-)\n\n> I don't think cleaning it up needs to be part of your series, but it\n> might be nice low-hanging fruit for somebody to clean up on top.\n\nI agree.\n\nI briefly wondered if we want to add a check to ensure uniqueness of\nthese cmdmode letters in parse_options_check(), but that would\nforbid us from having synonymous options (e.g. \"am --continue\" and\n\"am --resolved\" both map to the same), so it would not work.\n\n"},{"id":"299853","messageId":"0ee82126-3fae-723a-ab89-b5794c4abc74@web.de","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608191656080.4924@virtualbox","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-08-22T16:51:36Z","receivedAt":"2016-08-22T16:52:03Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 19.08.16 17:00, Johannes Schindelin wrote:\n> Hi Torsten,\n>\n> On Fri, 19 Aug 2016, Torsten Bögershausen wrote:\n>\n>> On Thu, Aug 18, 2016 at 02:46:17PM +0200, Johannes Schindelin wrote:\n>>\n>>> +--filters::\n>>> +\tShow the content as transformed by the filters configured in\n>> Minor comment:\n>> s/transformed/converted/ ?\n> Sure.\n>\n>> Does it make sense to be more specific here:\n>> The order of conversion is\n>> - ident\n>> - CRLF\n>> - smudge\n> I do not think it makes sense to complexify the documentation in that\n> manner. The filters should always be applied in the same order, methinks,\n> and it would only clutter the man page to repeat that order here.\nCan we can shorten the description and have something like this:\n\n--filters::\n+\tShow the content converted by the filters configured in\n+\tthe current working tree for the given <path>. \n+ \t<object> has to be of the form <tree-ish>:<path> or :<path>.\n+\n\n\n"},{"id":"300032","messageId":"alpine.DEB.2.20.1608240957040.4924@virtualbox","threadId":"43877","inReplyTo":"xmqqy43s3fin.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T07:57:28Z","receivedAt":"2016-08-24T07:57:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 19 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> I think I saw some code to ensure \"when giving this option you need\n> >> that option in effect, too\"; they should be tested here, too, no?\n> >\n> > No, I would rather not test for that. These conditionals are purely for\n> > any user's convenience, in case they specify an option that has no effect.\n> > They are absolutely not essential for the function introduced in this\n> > patch series.\n> \n> I didn't say \"you would want to test these, no?\", did I?\n> \n> I do not want to see bugreports that say \"I wanted to use this new\n> feature and by mistake gave only --path without giving --filter; Git\n> should have complained.  I found a bug, hooray!\" when somebody in\n> the future refactors the command line option parsing and breaks the\n> check you already have.\n\nI added a test to verify that --path without --filters nor --textconv\ncomplains.\n\nCiao,\nDscho\n"},{"id":"300033","messageId":"alpine.DEB.2.20.1608240958070.4924@virtualbox","threadId":"43877","inReplyTo":"0ee82126-3fae-723a-ab89-b5794c4abc74@web.de","subject":"Re: [PATCH 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T08:00:09Z","receivedAt":"2016-08-24T08:00:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Torsten,\n\nOn Mon, 22 Aug 2016, Torsten Bögershausen wrote:\n\n> On 19.08.16 17:00, Johannes Schindelin wrote:\n> >\n> > On Fri, 19 Aug 2016, Torsten Bögershausen wrote:\n> >\n> >> On Thu, Aug 18, 2016 at 02:46:17PM +0200, Johannes Schindelin wrote:\n> >>\n> >>> +--filters::\n> >>> +\tShow the content as transformed by the filters configured in\n> >> Minor comment:\n> >> s/transformed/converted/ ?\n> > Sure.\n> >\n> >> Does it make sense to be more specific here:\n> >> The order of conversion is\n> >> - ident\n> >> - CRLF\n> >> - smudge\n> > I do not think it makes sense to complexify the documentation in that\n> > manner. The filters should always be applied in the same order, methinks,\n> > and it would only clutter the man page to repeat that order here.\n> Can we can shorten the description and have something like this:\n> \n> --filters::\n> +\tShow the content converted by the filters configured in\n> +\tthe current working tree for the given <path>. \n> + \t<object> has to be of the form <tree-ish>:<path> or :<path>.\n\nI do not want it shortened *that* much. I, for one, would be confused\nreading about filters, as there are so many of them. So while I do not\nwant cat-file's man page to include an extensive description how filters\nwork, I do want it to have an indication which filters this option is\ntalking about.\n\nCiao,\nDscho"},{"id":"300040","messageId":"89fdd570345a1b092024e5b8e608852f0ccc94fc.1472041389.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T12:23:46Z","receivedAt":"2016-08-24T12:24:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"With this patch, --batch can be combined with --textconv or --filters.\nFor this to work, the input needs to have the form\n\n\t<object name><single white space><path>\n\nso that the filters can be chosen appropriately.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 18 +++++++++++-----\n builtin/cat-file.c             | 49 +++++++++++++++++++++++++++++++++++++-----\n t/t8010-cat-file-filters.sh    | 10 +++++++++\n 3 files changed, 67 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 4fa9041..204541c 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>\n-'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n+'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]\n \n DESCRIPTION\n -----------\n@@ -20,7 +20,11 @@ object type, or `-s` is used to find the object size, or `--textconv` or\n `--filters` is used (which imply type \"blob\").\n \n In the second form, a list of objects (separated by linefeeds) is provided on\n-stdin, and the SHA-1, type, and size of each object is printed on stdout.\n+stdin, and the SHA-1, type, and size of each object is printed on stdout. The\n+output format can be overridden using the optional `<format>` argument. If\n+either `--textconv` or `--filters` was specified, the input is expected to\n+list the object names followed by the path name, separated by a single white\n+space, so that the appropriate drivers can be determined.\n \n OPTIONS\n -------\n@@ -72,13 +76,17 @@ OPTIONS\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\n-\ton stdin.  May not be combined with any other options or arguments.\n-\tSee the section `BATCH OUTPUT` below for details.\n+\ton stdin.  May not be combined with any other options or arguments\n+\texcept `--textconv` or `--filters`, in which case the input lines\n+\talso need to specify the path, separated by white space.  See the\n+\tsection `BATCH OUTPUT` below for details.\n \n --batch-check::\n --batch-check=<format>::\n \tPrint object information for each object provided on stdin.  May\n-\tnot be combined with any other options or arguments.  See the\n+\tnot be combined with any other options or arguments except\n+\t`--textconv` or `--filters`, in which case the input lines also\n+\tneed to specify the path, separated by white space.  See the\n \tsection `BATCH OUTPUT` below for details.\n \n --batch-all-objects::\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 2c799ac..f8a3a08 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -17,6 +17,7 @@ struct batch_options {\n \tint print_contents;\n \tint buffer_output;\n \tint all_objects;\n+\tint cmdmode; /* may be 'w' or 'c' for --filters or --textconv */\n \tconst char *format;\n };\n \n@@ -285,7 +286,32 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \tif (data->type == OBJ_BLOB) {\n \t\tif (opt->buffer_output)\n \t\t\tfflush(stdout);\n-\t\tif (stream_blob_to_fd(1, sha1, NULL, 0) < 0)\n+\t\tif (opt->cmdmode) {\n+\t\t\tchar *contents;\n+\t\t\tunsigned long size;\n+\n+\t\t\tif (!data->rest)\n+\t\t\t\tdie(\"missing path for '%s'\", sha1_to_hex(sha1));\n+\n+\t\t\tif (opt->cmdmode == 'w') {\n+\t\t\t\tif (filter_object(data->rest, 0100644, sha1,\n+\t\t\t\t\t\t  &contents, &size))\n+\t\t\t\t\tdie(\"could not convert '%s' %s\",\n+\t\t\t\t\t    sha1_to_hex(sha1), data->rest);\n+\t\t\t} else if (opt->cmdmode == 'c') {\n+\t\t\t\tenum object_type type;\n+\t\t\t\tif (!textconv_object(data->rest, 0100644, sha1,\n+\t\t\t\t\t\t     1, &contents, &size))\n+\t\t\t\t\tcontents = read_sha1_file(sha1, &type,\n+\t\t\t\t\t\t\t\t  &size);\n+\t\t\t\tif (!contents)\n+\t\t\t\t\tdie(\"could not convert '%s' %s\",\n+\t\t\t\t\t    sha1_to_hex(sha1), data->rest);\n+\t\t\t} else\n+\t\t\t\tdie(\"BUG: invalid cmdmode: %c\", opt->cmdmode);\n+\t\t\tbatch_write(opt, contents, size);\n+\t\t\tfree(contents);\n+\t\t} else if (stream_blob_to_fd(1, sha1, NULL, 0) < 0)\n \t\t\tdie(\"unable to stream %s to stdout\", sha1_to_hex(sha1));\n \t}\n \telse {\n@@ -422,6 +448,8 @@ static int batch_objects(struct batch_options *opt)\n \tdata.mark_query = 1;\n \tstrbuf_expand(&buf, opt->format, expand_format, &data);\n \tdata.mark_query = 0;\n+\tif (opt->cmdmode)\n+\t\tdata.split_on_whitespace = 1;\n \n \tif (opt->all_objects) {\n \t\tstruct object_info empty;\n@@ -487,7 +515,7 @@ static int batch_objects(struct batch_options *opt)\n \n static const char * const cat_file_usage[] = {\n \tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>\"),\n-\tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n+\tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv|--filters]\"),\n \tNULL\n };\n \n@@ -558,7 +586,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);\n \n \tif (opt) {\n-\t\tif (argc == 1)\n+\t\tif (batch.enabled && (opt == 'c' || opt == 'w'))\n+\t\t\tbatch.cmdmode = opt;\n+\t\telse if (argc == 1)\n \t\t\tobj_name = argv[0];\n \t\telse\n \t\t\tusage_with_options(cat_file_usage, options);\n@@ -570,8 +600,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\t} else\n \t\t\tusage_with_options(cat_file_usage, options);\n \t}\n-\tif (batch.enabled && (opt || argc)) {\n-\t\tusage_with_options(cat_file_usage, options);\n+\tif (batch.enabled) {\n+\t\tif (batch.cmdmode != opt || argc)\n+\t\t\tusage_with_options(cat_file_usage, options);\n+\t\tif (batch.cmdmode && batch.all_objects)\n+\t\t\tdie(\"--batch-all-objects cannot be combined with \"\n+\t\t\t    \"--textconv nor with --filters\");\n \t}\n \n \tif ((batch.follow_symlinks || batch.all_objects) && !batch.enabled) {\n@@ -583,6 +617,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(cat_file_usage, options);\n \t}\n \n+\tif (force_path && batch.enabled) {\n+\t\terror(\"--path=<path> incompatible with --batch\");\n+\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\n \tif (batch.buffer_output < 0)\n \t\tbatch.buffer_output = batch.all_objects;\n \ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nindex 0d5c33e..acdfa09 100755\n--- a/t/t8010-cat-file-filters.sh\n+++ b/t/t8010-cat-file-filters.sh\n@@ -51,4 +51,14 @@ test_expect_success '----path=<path> complains without --textconv/--filters' '\n \tgrep \"path.*needs.*filters\" err\n '\n \n+test_expect_success 'cat-file --textconv --batch works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n+\tprintf \"%s hello.txt\\n%s hello\\n\" $sha1 $sha1 |\n+\tgit cat-file --textconv --batch >actual &&\n+\tprintf \"%s blob 6\\nuryyb\\r\\n\\n%s blob 6\\nhello\\n\\n\" \\\n+\t\t$sha1 $sha1 >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.10.0.rc1.99.gcd66998\n"},{"id":"300041","messageId":"320f5e862e8df12bbd1d918f0b347aeacbd25d17.1472041389.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T12:23:39Z","receivedAt":"2016-08-24T12:24:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The --filters option applies the convert_to_working_tree() filter for\nthe path when showing the contents of a regular file blob object.\n\nThis feature comes in handy when a 3rd-party tool wants to work with\nthe contents of files from past revisions as if they had been checked\nout, but without detouring via temporary files.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 12 +++++++++---\n builtin/cat-file.c             | 41 ++++++++++++++++++++++++++++++++++++++++-\n t/t8010-cat-file-filters.sh    | 34 ++++++++++++++++++++++++++++++++++\n 3 files changed, 83 insertions(+), 4 deletions(-)\n create mode 100755 t/t8010-cat-file-filters.sh\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 071029b..537d02c 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -9,15 +9,15 @@ git-cat-file - Provide content or type and size information for repository objec\n SYNOPSIS\n --------\n [verse]\n-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv ) <object>\n+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n 'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n \n DESCRIPTION\n -----------\n In its first form, the command provides the content or the type of an object in\n the repository. The type is required unless `-t` or `-p` is used to find the\n-object type, or `-s` is used to find the object size, or `--textconv` is used\n-(which implies type \"blob\").\n+object type, or `-s` is used to find the object size, or `--textconv` or\n+`--filters` is used (which imply type \"blob\").\n \n In the second form, a list of objects (separated by linefeeds) is provided on\n stdin, and the SHA-1, type, and size of each object is printed on stdout.\n@@ -58,6 +58,12 @@ OPTIONS\n \torder to apply the filter to the content recorded in the index at\n \t<path>.\n \n+--filters::\n+\tShow the content as converted by the filters configured in\n+\tthe current working tree for the given <path> (i.e. smudge filters,\n+\tend-of-line conversion, etc). In this case, <object> has to be of\n+\tthe form <tree-ish>:<path>, or :<path>.\n+\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 2dfe626..0b74afa 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -20,6 +20,33 @@ struct batch_options {\n \tconst char *format;\n };\n \n+static int filter_object(const char *path, unsigned mode,\n+\t\t\t const unsigned char *sha1,\n+\t\t\t char **buf, unsigned long *size)\n+{\n+\tenum object_type type;\n+\n+\t*buf = read_sha1_file(sha1, &type, size);\n+\tif (!*buf)\n+\t\treturn error(_(\"cannot read object %s '%s'\"),\n+\t\t\tsha1_to_hex(sha1), path);\n+\tif (type != OBJ_BLOB) {\n+\t\tfree(*buf);\n+\t\treturn error(_(\"blob expected for %s '%s'\"),\n+\t\t\tsha1_to_hex(sha1), path);\n+\t}\n+\tif (S_ISREG(mode)) {\n+\t\tstruct strbuf strbuf = STRBUF_INIT;\n+\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n+\t\t\tfree(*buf);\n+\t\t\t*size = strbuf.len;\n+\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t\tint unknown_type)\n {\n@@ -61,6 +88,16 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tcase 'e':\n \t\treturn !has_sha1_file(sha1);\n \n+\tcase 'w':\n+\t\tif (!obj_context.path[0])\n+\t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n+\t\t\t    \"<sha1:path>\", obj_name);\n+\n+\t\tif (filter_object(obj_context.path, obj_context.mode,\n+\t\t\t\t  sha1, &buf, &size))\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n \tcase 'c':\n \t\tif (!obj_context.path[0])\n \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n@@ -440,7 +477,7 @@ static int batch_objects(struct batch_options *opt)\n }\n \n static const char * const cat_file_usage[] = {\n-\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv) <object>\"),\n+\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) <object>\"),\n \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n \tNULL\n };\n@@ -486,6 +523,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('p', NULL, &opt, N_(\"pretty-print object's content\"), 'p'),\n \t\tOPT_CMDMODE(0, \"textconv\", &opt,\n \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n+\t\tOPT_CMDMODE(0, \"filters\", &opt,\n+\t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nnew file mode 100755\nindex 0000000..e466634\n--- /dev/null\n+++ b/t/t8010-cat-file-filters.sh\n@@ -0,0 +1,34 @@\n+#!/bin/sh\n+\n+test_description='git cat-file filters support'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup ' '\n+\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n+\techo \"hello\" | append_cr >world.txt &&\n+\tgit add .gitattributes world.txt &&\n+\ttest_tick &&\n+\tgit commit -m \"Initial commit\"\n+'\n+\n+has_cr () {\n+\ttr '\\015' Q <\"$1\" | grep Q >/dev/null\n+}\n+\n+test_expect_success 'no filters with `git show`' '\n+\tgit show HEAD:world.txt >actual &&\n+\t! has_cr actual\n+\n+'\n+\n+test_expect_success 'no filters with cat-file' '\n+\tgit cat-file blob HEAD:world.txt >actual &&\n+\t! has_cr actual\n+'\n+\n+test_expect_success 'cat-file --filters converts to worktree version' '\n+\tgit cat-file --filters HEAD:world.txt >actual &&\n+\thas_cr actual\n+'\n+\n+test_done\n-- \n2.10.0.rc1.99.gcd66998\n\n\n"},{"id":"300042","messageId":"e913d0e680bc1b976f53bc36960444529cf379eb.1472041389.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 1/4] cat-file: fix a grammo in the man page","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T12:23:36Z","receivedAt":"2016-08-24T12:24:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\"... has be ...\" -> \"... has to be ...\"\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 18d03d8..071029b 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -54,8 +54,9 @@ OPTIONS\n \n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n-\t<object> has be of the form <tree-ish>:<path>, or :<path> in order\n-\tto apply the filter to the content recorded in the index at <path>.\n+\t<object> has to be of the form <tree-ish>:<path>, or :<path> in\n+\torder to apply the filter to the content recorded in the index at\n+\t<path>.\n \n --batch::\n --batch=<format>::\n-- \n2.10.0.rc1.99.gcd66998\n\n\n"},{"id":"300043","messageId":"cover.1472041389.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1471524357.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T12:23:30Z","receivedAt":"2016-08-24T12:24:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When third-party tools need to access to contents of blobs in the\ndatabase, they might be more interested in the worktree version than in\nthe \"clean\" version of said contents.\n\nThis branch introduces the --filters option to make that happen, the\n--use-path option to provide the path separately if the blob name rather\nthan the tree name is availale, and offers batch support in which case\nit expects the object names and the path on its input lines, separated\nby white space.\n\nThe new --filters option is an obvious sibling of --textconv, and shares\nthe peculiar feature that the drivers (and end-of-line convention) are\ndetermined from the current worktree, not from the attributes stored in\nthe revision that may have been part of the object name.\n\nAs --textconv is so similar to --filters, it was taught to understand\nthe --use-path option and it was made compatible with batch mode, too.\n\nI briefly considered teaching the batch mode to extract the path from\nobject names if they are specified as <tree-ish>:<path>. The changes\nwould be quite intrusive, though, and uglify the code substanitially. So\nI decided against that.\n\nChanges vs v2:\n\n- two commit messages were touched up\n\n- --use-path=<path> was renamed to --path=<path>\n\n- a test was added to verify that --path without --textconv/--filters\n  errors out with helpful advice\n\n\nJohannes Schindelin (4):\n  cat-file: fix a grammo in the man page\n  cat-file: introduce the --filters option\n  cat-file --textconv/--filters: allow specifying the path separately\n  cat-file: support --textconv/--filters in batch mode\n\n Documentation/git-cat-file.txt |  40 +++++++++++----\n builtin/cat-file.c             | 110 ++++++++++++++++++++++++++++++++++++++---\n t/t8010-cat-file-filters.sh    |  64 ++++++++++++++++++++++++\n 3 files changed, 196 insertions(+), 18 deletions(-)\n create mode 100755 t/t8010-cat-file-filters.sh\n\nPublished-As: https://github.com/dscho/git/releases/tag/cat-file-filters-v2\nFetch-It-Via: git fetch https://github.com/dscho/git cat-file-filters-v2\n\nInterdiff vs v1:\n\n diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\n index 1f4d954..204541c 100644\n --- a/Documentation/git-cat-file.txt\n +++ b/Documentation/git-cat-file.txt\n @@ -9,7 +9,7 @@ git-cat-file - Provide content or type and size information for repository objec\n  SYNOPSIS\n  --------\n  [verse]\n -'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--use-path=<path>] <object>\n +'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>\n  'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]\n  \n  DESCRIPTION\n @@ -63,12 +63,12 @@ OPTIONS\n  \t<path>.\n  \n  --filters::\n -\tShow the content as transformed by the filters configured in\n +\tShow the content as converted by the filters configured in\n  \tthe current working tree for the given <path> (i.e. smudge filters,\n  \tend-of-line conversion, etc). In this case, <object> has to be of\n  \tthe form <tree-ish>:<path>, or :<path>.\n  \n ---use-path=<path>::\n +--path=<path>::\n  \tFor use with --textconv or --filters, to allow specifying an object\n  \tname and a path separately, e.g. when it is difficult to figure out\n  \tthe revision from which the blob came.\n diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n index 5f91cf4..f8a3a08 100644\n --- a/builtin/cat-file.c\n +++ b/builtin/cat-file.c\n @@ -61,6 +61,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n  \tstruct object_info oi = {NULL};\n  \tstruct strbuf sb = STRBUF_INIT;\n  \tunsigned flags = LOOKUP_REPLACE_OBJECT;\n +\tconst char *path = force_path;\n  \n  \tif (unknown_type)\n  \t\tflags |= LOOKUP_UNKNOWN_OBJECT;\n @@ -68,6 +69,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n  \tif (get_sha1_with_context(obj_name, 0, sha1, &obj_context))\n  \t\tdie(\"Not a valid object name %s\", obj_name);\n  \n +\tif (!path)\n +\t\tpath = obj_context.path;\n +\telse if (obj_context.mode == S_IFINVALID)\n +\t\tobj_context.mode = 0100644;\n +\n  \tbuf = NULL;\n  \tswitch (opt) {\n  \tcase 't':\n @@ -92,23 +98,21 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n  \t\treturn !has_sha1_file(sha1);\n  \n  \tcase 'w':\n -\t\tif (!force_path && !obj_context.path[0])\n +\t\tif (!path[0])\n  \t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n  \t\t\t    \"<sha1:path>\", obj_name);\n  \n -\t\tif (filter_object(force_path ? force_path : obj_context.path,\n -\t\t\t\t  force_path ? 0100644 : obj_context.mode,\n +\t\tif (filter_object(path, obj_context.mode,\n  \t\t\t\t  sha1, &buf, &size))\n  \t\t\treturn -1;\n  \t\tbreak;\n  \n  \tcase 'c':\n -\t\tif (!force_path && !obj_context.path[0])\n +\t\tif (!path[0])\n  \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n  \t\t\t    obj_name);\n  \n -\t\tif (textconv_object(force_path ? force_path : obj_context.path,\n -\t\t\t\t    force_path ? 0100644 : obj_context.mode,\n +\t\tif (textconv_object(path, obj_context.mode,\n  \t\t\t\t    sha1, 1, &buf, &size))\n  \t\t\tbreak;\n  \n @@ -510,7 +514,7 @@ static int batch_objects(struct batch_options *opt)\n  }\n  \n  static const char * const cat_file_usage[] = {\n -\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--use-path=<path>] <object>\"),\n +\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>\"),\n  \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv|--filters]\"),\n  \tNULL\n  };\n @@ -558,7 +562,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n  \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n  \t\tOPT_CMDMODE(0, \"filters\", &opt,\n  \t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n -\t\tOPT_STRING(0, \"use-path\", &force_path, N_(\"blob\"),\n +\t\tOPT_STRING(0, \"path\", &force_path, N_(\"blob\"),\n  \t\t\t   N_(\"use a specific path for --textconv/--filters\")),\n  \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n  \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n @@ -609,12 +613,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n  \t}\n  \n  \tif (force_path && opt != 'c' && opt != 'w') {\n -\t\terror(\"--use-path=<path> needs --textconv or --filters\");\n +\t\terror(\"--path=<path> needs --textconv or --filters\");\n  \t\tusage_with_options(cat_file_usage, options);\n  \t}\n  \n  \tif (force_path && batch.enabled) {\n -\t\terror(\"--use-path=<path> incompatible with --batch\");\n +\t\terror(\"--path=<path> incompatible with --batch\");\n  \t\tusage_with_options(cat_file_usage, options);\n  \t}\n  \n diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\n index 89ae868..acdfa09 100755\n --- a/t/t8010-cat-file-filters.sh\n +++ b/t/t8010-cat-file-filters.sh\n @@ -31,19 +31,26 @@ test_expect_success 'cat-file --filters converts to worktree version' '\n  \thas_cr actual\n  '\n  \n -test_expect_success 'cat-file --filters --use-path=<path> works' '\n +test_expect_success 'cat-file --filters --path=<path> works' '\n  \tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n -\tgit cat-file --filters --use-path=world.txt $sha1 >actual &&\n +\tgit cat-file --filters --path=world.txt $sha1 >actual &&\n  \thas_cr actual\n  '\n  \n -test_expect_success 'cat-file --textconv --use-path=<path> works' '\n +test_expect_success 'cat-file --textconv --path=<path> works' '\n  \tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n  \ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n -\tgit cat-file --textconv --use-path=hello.txt $sha1 >rot13 &&\n +\tgit cat-file --textconv --path=hello.txt $sha1 >rot13 &&\n  \ttest uryyb = \"$(cat rot13 | remove_cr)\"\n  '\n  \n +test_expect_success '----path=<path> complains without --textconv/--filters' '\n +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n +\ttest_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&\n +\ttest ! -s actual &&\n +\tgrep \"path.*needs.*filters\" err\n +'\n +\n  test_expect_success 'cat-file --textconv --batch works' '\n  \tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n  \ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n\n-- \n2.10.0.rc1.99.gcd66998\n\nbase-commit: 2632c897f74b1cc9b5533f467da459b9ec725538\n"},{"id":"300044","messageId":"d9e9d8b111efd161986aee32bb3ae0baec0dcf34.1472041389.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-24T12:23:43Z","receivedAt":"2016-08-24T12:25:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There are circumstances when it is relatively easy to figure out the\nobject name for a given path, but not the name of the containing tree.\nFor example, when looking at a diff generated by Git, the object names\nare recorded, but not the revision. As a matter of fact, the revisions\nfrom which the diff was generated may not even exist locally.\n\nIn such a case, the user would have to generate a fake revision just to\nbe able to use --textconv or --filters.\n\nLet's simplify this dramatically, because we do not really need that\nrevision at all: all we care about is that we know the path. In the\nscenario described above, we do know the path, and we just want to\nspecify it separately from the object name.\n\nExample usage:\n\n\tgit cat-file --textconv --path=main.c 0f1937fd\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt |  7 ++++++-\n builtin/cat-file.c             | 26 +++++++++++++++++++++-----\n t/t8010-cat-file-filters.sh    | 20 ++++++++++++++++++++\n 3 files changed, 47 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 537d02c..4fa9041 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -9,7 +9,7 @@ git-cat-file - Provide content or type and size information for repository objec\n SYNOPSIS\n --------\n [verse]\n-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>\n 'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n \n DESCRIPTION\n@@ -64,6 +64,11 @@ OPTIONS\n \tend-of-line conversion, etc). In this case, <object> has to be of\n \tthe form <tree-ish>:<path>, or :<path>.\n \n+--path=<path>::\n+\tFor use with --textconv or --filters, to allow specifying an object\n+\tname and a path separately, e.g. when it is difficult to figure out\n+\tthe revision from which the blob came.\n+\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 0b74afa..2c799ac 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -20,6 +20,8 @@ struct batch_options {\n \tconst char *format;\n };\n \n+static const char *force_path;\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const unsigned char *sha1,\n \t\t\t char **buf, unsigned long *size)\n@@ -58,6 +60,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tstruct object_info oi = {NULL};\n \tstruct strbuf sb = STRBUF_INIT;\n \tunsigned flags = LOOKUP_REPLACE_OBJECT;\n+\tconst char *path = force_path;\n \n \tif (unknown_type)\n \t\tflags |= LOOKUP_UNKNOWN_OBJECT;\n@@ -65,6 +68,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tif (get_sha1_with_context(obj_name, 0, sha1, &obj_context))\n \t\tdie(\"Not a valid object name %s\", obj_name);\n \n+\tif (!path)\n+\t\tpath = obj_context.path;\n+\telse if (obj_context.mode == S_IFINVALID)\n+\t\tobj_context.mode = 0100644;\n+\n \tbuf = NULL;\n \tswitch (opt) {\n \tcase 't':\n@@ -89,21 +97,22 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\treturn !has_sha1_file(sha1);\n \n \tcase 'w':\n-\t\tif (!obj_context.path[0])\n+\t\tif (!path[0])\n \t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n \t\t\t    \"<sha1:path>\", obj_name);\n \n-\t\tif (filter_object(obj_context.path, obj_context.mode,\n+\t\tif (filter_object(path, obj_context.mode,\n \t\t\t\t  sha1, &buf, &size))\n \t\t\treturn -1;\n \t\tbreak;\n \n \tcase 'c':\n-\t\tif (!obj_context.path[0])\n+\t\tif (!path[0])\n \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n \t\t\t    obj_name);\n \n-\t\tif (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))\n+\t\tif (textconv_object(path, obj_context.mode,\n+\t\t\t\t    sha1, 1, &buf, &size))\n \t\t\tbreak;\n \n \tcase 'p':\n@@ -477,7 +486,7 @@ static int batch_objects(struct batch_options *opt)\n }\n \n static const char * const cat_file_usage[] = {\n-\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) <object>\"),\n+\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>\"),\n \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n \tNULL\n };\n@@ -525,6 +534,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n \t\tOPT_CMDMODE(0, \"filters\", &opt,\n \t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n+\t\tOPT_STRING(0, \"path\", &force_path, N_(\"blob\"),\n+\t\t\t   N_(\"use a specific path for --textconv/--filters\")),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\n@@ -567,6 +578,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(cat_file_usage, options);\n \t}\n \n+\tif (force_path && opt != 'c' && opt != 'w') {\n+\t\terror(\"--path=<path> needs --textconv or --filters\");\n+\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\n \tif (batch.buffer_output < 0)\n \t\tbatch.buffer_output = batch.all_objects;\n \ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nindex e466634..0d5c33e 100755\n--- a/t/t8010-cat-file-filters.sh\n+++ b/t/t8010-cat-file-filters.sh\n@@ -31,4 +31,24 @@ test_expect_success 'cat-file --filters converts to worktree version' '\n \thas_cr actual\n '\n \n+test_expect_success 'cat-file --filters --path=<path> works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\tgit cat-file --filters --path=world.txt $sha1 >actual &&\n+\thas_cr actual\n+'\n+\n+test_expect_success 'cat-file --textconv --path=<path> works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n+\tgit cat-file --textconv --path=hello.txt $sha1 >rot13 &&\n+\ttest uryyb = \"$(cat rot13 | remove_cr)\"\n+'\n+\n+test_expect_success '----path=<path> complains without --textconv/--filters' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&\n+\ttest ! -s actual &&\n+\tgrep \"path.*needs.*filters\" err\n+'\n+\n test_done\n-- \n2.10.0.rc1.99.gcd66998\n\n\n"},{"id":"300068","messageId":"xmqqk2f6rvx9.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T16:09:06Z","receivedAt":"2016-08-24T16:09:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n>  diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n>  index 5f91cf4..f8a3a08 100644\n>  --- a/builtin/cat-file.c\n>  +++ b/builtin/cat-file.c\n>  @@ -61,6 +61,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>   \tstruct object_info oi = {NULL};\n>   \tstruct strbuf sb = STRBUF_INIT;\n>   \tunsigned flags = LOOKUP_REPLACE_OBJECT;\n>  +\tconst char *path = force_path;\n>   \n>   \tif (unknown_type)\n>   \t\tflags |= LOOKUP_UNKNOWN_OBJECT;\n>  @@ -68,6 +69,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>   \tif (get_sha1_with_context(obj_name, 0, sha1, &obj_context))\n>   \t\tdie(\"Not a valid object name %s\", obj_name);\n>   \n>  +\tif (!path)\n>  +\t\tpath = obj_context.path;\n>  +\telse if (obj_context.mode == S_IFINVALID)\n>  +\t\tobj_context.mode = 0100644;\n>  +\n>   \tbuf = NULL;\n>   \tswitch (opt) {\n>   \tcase 't':\n\nThe above two hunks make all the difference in the ease of reading\nthe remainder of the function.  Very good.\n\n>  +test_expect_success '----path=<path> complains without --textconv/--filters' '\n>  +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n>  +\ttest_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&\n>  +\ttest ! -s actual &&\n>  +\tgrep \"path.*needs.*filters\" err\n>  +'\n\nThis will need to become test_i18ngrep once the error message is\nmade translatable, but it is correct for now.  I personally think\nthere is no need to check \"actual\" or \"err\", though---just running\ncat-file under test_must_fail should be sufficient.\n\nThanks, will queue.\n"},{"id":"300073","messageId":"20160824161939.d2h4qlaxhhi6limm@sigill.intra.peff.net","threadId":"43877","inReplyTo":"xmqqk2f6rvx9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-08-24T16:19:40Z","receivedAt":"2016-08-24T16:26:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Aug 24, 2016 at 09:09:06AM -0700, Junio C Hamano wrote:\n\n> >  +\tif (!path)\n> >  +\t\tpath = obj_context.path;\n> >  +\telse if (obj_context.mode == S_IFINVALID)\n> >  +\t\tobj_context.mode = 0100644;\n> >  +\n> >   \tbuf = NULL;\n> >   \tswitch (opt) {\n> >   \tcase 't':\n> \n> The above two hunks make all the difference in the ease of reading\n> the remainder of the function.  Very good.\n\nYeah, I agree. Though it took me a moment to figure out why we were\nsetting obj_context.mode but not obj_context.path; the reason is that\n\"mode\" is convenient to use as local storage, but \"path\" is not, because\nit is not a pointer but an array.\n\nSo it would have been a little clearer to me as:\n\n  const char *path;\n  unsigned mode;\n  ...\n  if (!force_path) {\n\t/* use file info from sha1 lookup */\n\tpath = obj_context.path;\n\tmode = obj_context.mode;\n  } else {\n\t/* use path requested by user, and assume it is a regular file */\n\tpath = force_path;\n\tmode = 0100644;\n  }\n\nbut I don't know if that is even worth a re-roll.\n\n> >  +test_expect_success '----path=<path> complains without --textconv/--filters' '\n> >  +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n> >  +\ttest_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&\n> >  +\ttest ! -s actual &&\n> >  +\tgrep \"path.*needs.*filters\" err\n> >  +'\n> \n> This will need to become test_i18ngrep once the error message is\n> made translatable, but it is correct for now.  I personally think\n> there is no need to check \"actual\" or \"err\", though---just running\n> cat-file under test_must_fail should be sufficient.\n> \n> Thanks, will queue.\n\nThe whole thing looks good to me, except for the weird doubled \"--\" in\nthe test description you quoted above. :)\n\n-Peff\n"},{"id":"300082","messageId":"xmqqr39eqevk.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"20160824161939.d2h4qlaxhhi6limm@sigill.intra.peff.net","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T17:02:39Z","receivedAt":"2016-08-24T17:05:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Wed, Aug 24, 2016 at 09:09:06AM -0700, Junio C Hamano wrote:\n>\n>> >  +\tif (!path)\n>> >  +\t\tpath = obj_context.path;\n>> >  +\telse if (obj_context.mode == S_IFINVALID)\n>> >  +\t\tobj_context.mode = 0100644;\n>> >  +\n>> >   \tbuf = NULL;\n>> >   \tswitch (opt) {\n>> >   \tcase 't':\n>> \n>> The above two hunks make all the difference in the ease of reading\n>> the remainder of the function.  Very good.\n>\n> Yeah, I agree. Though it took me a moment to figure out why we were\n> setting obj_context.mode but not obj_context.path; the reason is that\n> \"mode\" is convenient to use as local storage, but \"path\" is not, because\n> it is not a pointer but an array.\n\nWait a minute.  Why is it a cascaded if/elseif, not two independent\nif statements that gives a default value?  In other words, wouldn't\nthese two independent and orthogonal decisions?\n\n * When forced to use some path, we ignore obj_context.path\n\n * Whether we are forced to use a path or not, if we do not know the\n   mode from the lookup context, we want to use the regular blob\n   mode.\n\nSo that part of the patch is wrong after all, I would have to say.\n\n\tif (!path)\n        \tpath = obj_context.path;\n\tif (obj_context.mode == S_IFINVALID)\n        \tobj_context.mode = 0100644;\n\nor something like that, perhaps.\n\n> So it would have been a little clearer to me as:\n>\n>   const char *path;\n>   unsigned mode;\n>   ...\n>   if (!force_path) {\n> \t/* use file info from sha1 lookup */\n> \tpath = obj_context.path;\n> \tmode = obj_context.mode;\n>   } else {\n> \t/* use path requested by user, and assume it is a regular file */\n> \tpath = force_path;\n> \tmode = 0100644;\n>   }\n\nHmph, if you read it that way, then if/elseif makes some sense, but\nwe need to assume that the obj_context.mode can be garbage and have\na fallback for it.\n\nJust like\n\n\tgit cat-file --filters --path=git.c HEAD:t\n\nwould error out because HEAD:t is not even a blob, I would expect\n\n\tgit cat-file --filters --path=git.c :RelNotes\n\nto error out, because the object itself _is_ known to be a\nblob that is not a regular file.\n\nAnd that kind of type checking will not be possible with \"if the\nuser gave us a path, assume it is a regular file\".\n"},{"id":"300084","messageId":"20160824173248.ami3hgadea5zjvf3@sigill.intra.peff.net","threadId":"43877","inReplyTo":"xmqqr39eqevk.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-08-24T17:32:48Z","receivedAt":"2016-08-24T17:32:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Aug 24, 2016 at 10:02:39AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > On Wed, Aug 24, 2016 at 09:09:06AM -0700, Junio C Hamano wrote:\n> >\n> >> >  +\tif (!path)\n> >> >  +\t\tpath = obj_context.path;\n> >> >  +\telse if (obj_context.mode == S_IFINVALID)\n> >> >  +\t\tobj_context.mode = 0100644;\n> >> >  +\n> >> >   \tbuf = NULL;\n> >> >   \tswitch (opt) {\n> >> >   \tcase 't':\n> >> \n> >> The above two hunks make all the difference in the ease of reading\n> >> the remainder of the function.  Very good.\n> >\n> > Yeah, I agree. Though it took me a moment to figure out why we were\n> > setting obj_context.mode but not obj_context.path; the reason is that\n> > \"mode\" is convenient to use as local storage, but \"path\" is not, because\n> > it is not a pointer but an array.\n> \n> Wait a minute.  Why is it a cascaded if/elseif, not two independent\n> if statements that gives a default value?  In other words, wouldn't\n> these two independent and orthogonal decisions?\n> \n>  * When forced to use some path, we ignore obj_context.path\n> \n>  * Whether we are forced to use a path or not, if we do not know the\n>    mode from the lookup context, we want to use the regular blob\n>    mode.\n> \n> So that part of the patch is wrong after all, I would have to say.\n> \n> \tif (!path)\n>         \tpath = obj_context.path;\n> \tif (obj_context.mode == S_IFINVALID)\n>         \tobj_context.mode = 0100644;\n> \n> or something like that, perhaps.\n\nOh, hrm, you are right. I assumed we wanted to force the mode when\n--path was in effect, but that is not what the original does. If you\nsay:\n\n  --path=foo HEAD:bar\n\nthen we will take the mode for \"bar\", whatever it is (maybe a tree or\nsymlink). But if you say:\n\n  --path=foo $(git rev-parse HEAD:bar)\n\nthen we will use 100644, regardless of what \"bar\" is in HEAD.\n\nI have not thought about it enough to know if that is a good thing or a\nbad thing. But I'll bet Dscho has, so I will wait for him to comment. :)\n\n> >   if (!force_path) {\n> > \t/* use file info from sha1 lookup */\n> > \tpath = obj_context.path;\n> > \tmode = obj_context.mode;\n> >   } else {\n> > \t/* use path requested by user, and assume it is a regular file */\n> > \tpath = force_path;\n> > \tmode = 0100644;\n> >   }\n> \n> Hmph, if you read it that way, then if/elseif makes some sense, but\n> we need to assume that the obj_context.mode can be garbage and have\n> a fallback for it.\n> \n> Just like\n> \n> \tgit cat-file --filters --path=git.c HEAD:t\n> \n> would error out because HEAD:t is not even a blob, I would expect\n> \n> \tgit cat-file --filters --path=git.c :RelNotes\n> \n> to error out, because the object itself _is_ known to be a\n> blob that is not a regular file.\n> \n> And that kind of type checking will not be possible with \"if the\n> user gave us a path, assume it is a regular file\".\n\nRight, I agree that is the outcome, but I just wasn't sure that the\nsecond case _should_ error out. IOW, does \"--filters --path\" mean \"treat\nthis as a regular file at path X\", or is the \"regular file\" part not\nimplied?\n\nI don't suppose anybody cares that much either way, but it feels weird\nto behave differently depending on how we looked up the blob (whereas\nfor the HEAD:t case, a tree is always a tree).\n\n-Peff\n"},{"id":"300086","messageId":"xmqqmvk2qcv8.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"320f5e862e8df12bbd1d918f0b347aeacbd25d17.1472041389.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T17:46:03Z","receivedAt":"2016-08-24T17:50:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> +static int filter_object(const char *path, unsigned mode,\n> +\t\t\t const unsigned char *sha1,\n> +\t\t\t char **buf, unsigned long *size)\n> +{\n> +\tenum object_type type;\n> +\n> +\t*buf = read_sha1_file(sha1, &type, size);\n> +\tif (!*buf)\n> +\t\treturn error(_(\"cannot read object %s '%s'\"),\n> +\t\t\tsha1_to_hex(sha1), path);\n> +\tif (type != OBJ_BLOB) {\n> +\t\tfree(*buf);\n> +\t\treturn error(_(\"blob expected for %s '%s'\"),\n> +\t\t\tsha1_to_hex(sha1), path);\n> +\t}\n> +\tif (S_ISREG(mode)) {\n> +\t\tstruct strbuf strbuf = STRBUF_INIT;\n> +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n> +\t\t\tfree(*buf);\n> +\t\t\t*size = strbuf.len;\n> +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n> +\t\t}\n> +\t}\n\nWhen we see a blob that is not ISREG, what is expected to happen?\nIs it an error?\n\nWe can argue both ways.\n\nCurrently the ONLY kind of blob that is not ISREG is a symbolic\nlink, and it might be OK to output it as-is without any conversion\n[*1*], in which case we can simply lose the S_ISREG(mode) check\naltogether (and \"mode\" parameter to this function).\n\nOn the other hand, because \"cat-file --filters\" is meant to be a\nsmaller-granularity operation that could be used as a building block\nto emulate what \"git checkout\" does, i.e. \"imagine that we had the\nblob in the index and checking it out from the path, and hand the\ncaller what would have been written out to the filesystem, so that\nthe convert_to_working_tree() logic does not have to be emulated in\nthe userspace\", erroring out when we see a symbolic link may be also\na valid way to handle it.  We know the usual CRLF and other conversions\ndo not apply to them.\n\nIn any case, silently succeeding without any output is probably what\nthe end-user least expects.\n\nIf we choose to fail the request, the necessary update to the test\nwould look like this, I think.\n\n> diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\n> new file mode 100755\n> index 0000000..e466634\n> --- /dev/null\n> +++ b/t/t8010-cat-file-filters.sh\n> @@ -0,0 +1,34 @@\n> +#!/bin/sh\n> +\n> +test_description='git cat-file filters support'\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup ' '\n> +\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n> +\techo \"hello\" | append_cr >world.txt &&\n> +\tgit add .gitattributes world.txt &&\n\n\tgit update-index --cacheinfo :world.txt,$EMPTY_BLOB,symlink &&\n\n> +\ttest_tick &&\n> +\tgit commit -m \"Initial commit\"\n> +'\n> +\n> +has_cr () {\n> +\ttr '\\015' Q <\"$1\" | grep Q >/dev/null\n> +}\n> +\n> +test_expect_success 'no filters with `git show`' '\n> +\tgit show HEAD:world.txt >actual &&\n> +\t! has_cr actual\n> +\n> +'\n> +\n> +test_expect_success 'no filters with cat-file' '\n> +\tgit cat-file blob HEAD:world.txt >actual &&\n> +\t! has_cr actual\n> +'\n> +\n> +test_expect_success 'cat-file --filters converts to worktree version' '\n> +\tgit cat-file --filters HEAD:world.txt >actual &&\n> +\thas_cr actual\n> +'\n\ntest_expect_success 'cat-file --filters rejects a non-blob' '\n\ttest_must_fail git cat-file --filters HEAD:\n'\n\ntest_expect_success 'cat-file --filters rejects a non-regular blob' '\n\ttest_must_fail git cat-file --filters HEAD:symlink\n'\n\nAnd if we choose to accept as long as it is a blob, then the last\nstep can lose test_must_fail (and perhaps the result needs to be\nchecked against \"hello\" without CR).\n\n\n[Footnote]\n\n*1* But of course other kinds of non-ISREG blob we would add later\n    may not be something you would want to write out as-is.\n\n"},{"id":"300087","messageId":"xmqqinuqqcor.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"d9e9d8b111efd161986aee32bb3ae0baec0dcf34.1472041389.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T17:49:56Z","receivedAt":"2016-08-24T17:50:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> @@ -65,6 +68,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \tif (get_sha1_with_context(obj_name, 0, sha1, &obj_context))\n>  \t\tdie(\"Not a valid object name %s\", obj_name);\n>  \n> +\tif (!path)\n> +\t\tpath = obj_context.path;\n> +\telse if (obj_context.mode == S_IFINVALID)\n> +\t\tobj_context.mode = 0100644;\n> +\n>  \tbuf = NULL;\n>  \tswitch (opt) {\n>  \tcase 't':\n\nMentioned elsewhere, but I think the above should be\n\n\tif (!path)\n        \tpath = obj_context.path;\n\n\tif (obj_context.mode == S_IFINVALID)\n        \tobj_context.mode = 0100644;\n\nIOW, even when there is an explicit path supplied, we should fall\nback to assumed \"regular blob\" mode, so that\n\n\tgit cat-file --filters --path=README $(git rev-parse :README)\n\nwould work as expected.\n"},{"id":"300089","messageId":"xmqqeg5eqck6.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"xmqqmvk2qcv8.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T17:52:41Z","receivedAt":"2016-08-24T17:53:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> +test_expect_success 'setup ' '\n>> +\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n>> +\techo \"hello\" | append_cr >world.txt &&\n>> +\tgit add .gitattributes world.txt &&\n>\n> \tgit update-index --cacheinfo :world.txt,$EMPTY_BLOB,symlink &&\n\nSorry, last-minute-edit-gone-bad-without-proofreading.  It should\nhave been something like:\n\n\tgit update-index --add --cacheinfo 160000,$EMPTY_BLOB,symlink &&\n\nor\n\n       \tsym=$(echo \"hello\" | git hash-objects --stdin -w) &&\n\tgit update-index --add --cacheinfo 160000,$sym,symlink &&\n"},{"id":"300090","messageId":"xmqqa8g2qcf3.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"20160824173248.ami3hgadea5zjvf3@sigill.intra.peff.net","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T17:55:44Z","receivedAt":"2016-08-24T17:55:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I don't suppose anybody cares that much either way, but it feels weird\n> to behave differently depending on how we looked up the blob (whereas\n> for the HEAD:t case, a tree is always a tree).\n\nI do not care strongly either way, but HEAD:RelNotes case we _know_\nit is not a regular blob, and discarding that info for the sake of\nbeing consistent with the common denominator case, instead of using\nit to point out a possible mistake, feels wrong, too.\n\nIn any case, not outputting anything and silently succeeding is\ndefinitely wrong ;-).\n"},{"id":"300096","messageId":"xmqqwpj6owgg.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"xmqqinuqqcor.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T18:25:51Z","receivedAt":"2016-08-24T18:26:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Mentioned elsewhere, but I think the above should be\n>\n> \tif (!path)\n>         \tpath = obj_context.path;\n>\n> \tif (obj_context.mode == S_IFINVALID)\n>         \tobj_context.mode = 0100644;\n>\n> IOW, even when there is an explicit path supplied, we should fall\n> back to assumed \"regular blob\" mode, so that\n>\n> \tgit cat-file --filters --path=README $(git rev-parse :README)\n>\n> would work as expected.\n\nActually, I am reading the conditional the other way, but the\nconclusion \"defaulting from unknown mode to regular blob is\nnecessary whether the user gave us a path or not\" is the same.\n\nThe current code may fail if --path is not available and 40-hex that\ndoes not give us any context of look up is given because it won't be\nable to decide how to filter, so using \"else if\" would not have\npractical difference there, but conceptually it still is wrong.\n"},{"id":"300504","messageId":"xmqqpoor8f0d.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-29T21:02:58Z","receivedAt":"2016-08-29T21:03:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> When third-party tools need to access to contents of blobs in the\n> database, they might be more interested in the worktree version than in\n> the \"clean\" version of said contents.\n\nJust a friendly reminder before you completely shift your attention\nto unrelated topics.  I think this topic is almost there; let's not\nstretch ourselves too thin by nibbling-here-nibbling-there and leaving\nloose ends untied.\n\nThanks.\n\n"},{"id":"300725","messageId":"alpine.DEB.2.20.1608312133150.129229@virtualbox","threadId":"43877","inReplyTo":"xmqqwpj6owgg.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T19:49:57Z","receivedAt":"2016-08-31T19:51:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 24 Aug 2016, Junio C Hamano wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > Mentioned elsewhere, but I think the above should be\n> >\n> > \tif (!path)\n> >         \tpath = obj_context.path;\n> >\n> > \tif (obj_context.mode == S_IFINVALID)\n> >         \tobj_context.mode = 0100644;\n> >\n> > IOW, even when there is an explicit path supplied, we should fall\n> > back to assumed \"regular blob\" mode, so that\n> >\n> > \tgit cat-file --filters --path=README $(git rev-parse :README)\n> >\n> > would work as expected.\n> \n> Actually, I am reading the conditional the other way, but the\n> conclusion \"defaulting from unknown mode to regular blob is\n> necessary whether the user gave us a path or not\" is the same.\n> \n> The current code may fail if --path is not available and 40-hex that\n> does not give us any context of look up is given because it won't be\n> able to decide how to filter, so using \"else if\" would not have\n> practical difference there, but conceptually it still is wrong.\n\nLet's translate the logic\n\n\tif (!path)\n\t\tpath = obj_context.path;\n\telse if (obj_context.mode == S_IFINVALID)\n\t\tobj_context.mode = 0100644;\n\ninto plain English.\n\nBasically, we have two cases:\n\n1) the user provided us with a --path option, in which case we only\n   override the mode if get_sha1_with_context() could not determine the\n   mode.\n\n2) the user did *not* provide us with a --path, in which case we keep the\n   mode exactly as determined by get_sha1_with_context().\n\nNow, the change you propose would change 2) such that we would *still*\noverride an undecided mode with 100644, even if the user did not bother to\nspecify a --path option.\n\nIt is true that it is currently impossible to infer a path from a blob ID\nwithout being able to infer also a mode. So the question is whether it\nmakes sense to allow cat-file to proceed on the assumption that it is a\nregular file if it does not know?\n\nI would say: no, it does not make sense.\n\nHowever, I do not want to hold this patch series up just by being\nstubborn.\n\nWill change it,\nDscho\n"},{"id":"300730","messageId":"xmqqinugzo97.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608312133150.129229@virtualbox","subject":"Re: [PATCH v2 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T20:17:56Z","receivedAt":"2016-08-31T20:18:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> However, I do not want to hold this patch series up just by being\n> stubborn.\n\nPeff and I disussed this further in the thread in which the message\n<xmqqa8g2qcf3.fsf@gitster.mtv.corp.google.com> appears, and agreed\nthat it does not matter that much either way.\n\nThe comment to [v2 2/4] would be more important than this one, I\nwould think.  What should happen when a blob that is not ISREG is\ngiven to filter_object()?  Giving a symlink contents as-is without\nfiltering would be OK.  Erroring out saying \"regular file blob\nexpected\" just like the function reacts to non-blob is also OK.\nJust being silent and not doing anything is probably not.\n\nThanks.\n\n"},{"id":"300732","messageId":"alpine.DEB.2.20.1608312153030.129229@virtualbox","threadId":"43877","inReplyTo":"xmqqmvk2qcv8.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T20:31:55Z","receivedAt":"2016-08-31T20:32:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 24 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > +static int filter_object(const char *path, unsigned mode,\n> > +\t\t\t const unsigned char *sha1,\n> > +\t\t\t char **buf, unsigned long *size)\n> > +{\n> > +\tenum object_type type;\n> > +\n> > +\t*buf = read_sha1_file(sha1, &type, size);\n> > +\tif (!*buf)\n> > +\t\treturn error(_(\"cannot read object %s '%s'\"),\n> > +\t\t\tsha1_to_hex(sha1), path);\n> > +\tif (type != OBJ_BLOB) {\n> > +\t\tfree(*buf);\n> > +\t\treturn error(_(\"blob expected for %s '%s'\"),\n> > +\t\t\tsha1_to_hex(sha1), path);\n> > +\t}\n> > +\tif (S_ISREG(mode)) {\n> > +\t\tstruct strbuf strbuf = STRBUF_INIT;\n> > +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n> > +\t\t\tfree(*buf);\n> > +\t\t\t*size = strbuf.len;\n> > +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n> > +\t\t}\n> > +\t}\n> \n> When we see a blob that is not ISREG, what is expected to happen?\n> Is it an error?\n\nThis is not a user-facing command, therefore we have to trust the caller\nthat they know what they are doing.\n\nAnd it is quite conceivable that a caller wants to simply apply filters\nwhenever a blob is specified, and simply not apply any filters when\nsomething else was specified.\n\nThat would be in line with specifying the --filters options on a path for\nwhich no filters are configured: the --filters option is basically a\nno-op, then.\n\n> In any case, silently succeeding without any output is probably what\n> the end-user least expects.\n\nExcept that 1) the command is not for an end-user, and 2) when calling\n`git cat-file --filters HEAD:directory/` the command does not silently\nsucceed:\n\n\terror: blob expected for <sha-1> 'directory/'\n\n> If we choose to fail the request, the necessary update to the test\n> would look like this, I think.\n\nQuite frankly, as cat-file is not an end-user-facing command, I think it\nis serious overkill to add more testing here.\n\nCiao,\nDscho\n"},{"id":"300734","messageId":"alpine.DEB.2.20.1608312233440.129229@virtualbox","threadId":"43877","inReplyTo":"xmqqpoor8f0d.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 0/4] cat-file: optionally convert to worktree version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T20:34:29Z","receivedAt":"2016-08-31T20:35:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 29 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > When third-party tools need to access to contents of blobs in the\n> > database, they might be more interested in the worktree version than in\n> > the \"clean\" version of said contents.\n> \n> Just a friendly reminder before you completely shift your attention\n> to unrelated topics.  I think this topic is almost there; let's not\n> stretch ourselves too thin by nibbling-here-nibbling-there and leaving\n> loose ends untied.\n\nI answered the comments and changed one thing locally. Will send out v3\ntomorrow.\n\nCiao,\nDscho\n"},{"id":"300737","messageId":"xmqqa8fszmm0.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1608312153030.129229@virtualbox","subject":"Re: [PATCH v2 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T20:53:27Z","receivedAt":"2016-08-31T20:53:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > +\tif (S_ISREG(mode)) {\n>> > +\t\tstruct strbuf strbuf = STRBUF_INIT;\n>> > +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n>> > +\t\t\tfree(*buf);\n>> > +\t\t\t*size = strbuf.len;\n>> > +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n>> > +\t\t}\n>> > +\t}\n>> \n>> When we see a blob that is not ISREG, what is expected to happen?\n>> Is it an error?\n>\n> This is not a user-facing command, therefore we have to trust the caller\n> that they know what they are doing.\n\nThe caller that knows what s/he is doing would rely on a documented\nbehaviour out of the command.  That behaviour hopefully is an\nintuitive and useful one for script writers.\n\nYou say\n\n> Quite frankly, as cat-file is not an end-user-facing command, I think it\n> is serious overkill to add more testing here.\n\nand I think you would need a serious attitude adjustment here.\nScriptors are also an important class of end-users and cat-file\ndirectly faces them.\n\nThinking about this one a bit more, as 'cat-file' especially with\nthe \"--filters\" option is the lowest-level way for scriptors to\nexternalize the data stored in Git object database to the\nrepresentation used in the outside world (in other words, it would\nbe a good ingredient if they want to implement what \"checkout\"\ndoes), I would expect that an intuitive behaviour for\n\n\tgit cat-file --filters HEAD:Makefile >Makefile\n\tgit cat-file --filters HEAD:RelNotes >Relnotes\n\tgit cat-file --filters HEAD:t >t\n\nto send the requested contents to the standard output stream, but\nerror out when the result of the command shown above would not\nmimick what \"checkout\" would leave in the filesystem.  IOW, the\nfirst one should succeed, the second and the third ones should fail\nthe same way to signal what is requested cannot be performed to the\nscript that is calling these commands.\n\n"},{"id":"301471","messageId":"c472ec57ea07584d96e8eea95175be9290d09edc.1473415827.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1473415827.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 1/4] cat-file: fix a grammo in the man page","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T10:10:44Z","receivedAt":"2016-09-09T10:10:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\"... has be ...\" -> \"... has to be ...\"\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 18d03d8..071029b 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -54,8 +54,9 @@ OPTIONS\n \n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n-\t<object> has be of the form <tree-ish>:<path>, or :<path> in order\n-\tto apply the filter to the content recorded in the index at <path>.\n+\t<object> has to be of the form <tree-ish>:<path>, or :<path> in\n+\torder to apply the filter to the content recorded in the index at\n+\t<path>.\n \n --batch::\n --batch=<format>::\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301472","messageId":"cover.1473415827.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1472041389.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 0/4] cat-file: optionally convert to worktree version","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T10:10:39Z","receivedAt":"2016-09-09T10:11:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When third-party tools need to access to contents of blobs in the\ndatabase, they might be more interested in the worktree version than in\nthe \"clean\" version of said contents.\n\nThis branch introduces the --filters option to make that happen, the\n--use-path option to provide the path separately if the blob name rather\nthan the tree name is availale, and offers batch support in which case\nit expects the object names and the path on its input lines, separated\nby white space.\n\nThe new --filters option is an obvious sibling of --textconv, and shares\nthe peculiar feature that the drivers (and end-of-line convention) are\ndetermined from the current worktree, not from the attributes stored in\nthe revision that may have been part of the object name.\n\nAs --textconv is so similar to --filters, it was taught to understand\nthe --use-path option and it was made compatible with batch mode, too.\n\nI briefly considered teaching the batch mode to extract the path from\nobject names if they are specified as <tree-ish>:<path>. The changes\nwould be quite intrusive, though, and uglify the code substanitially. So\nI decided against that.\n\nChanges vs v2:\n\n- always override unknown mode to imply 0100644, even if the user did\n  not specify the --path option.\n\n\nJohannes Schindelin (4):\n  cat-file: fix a grammo in the man page\n  cat-file: introduce the --filters option\n  cat-file --textconv/--filters: allow specifying the path separately\n  cat-file: support --textconv/--filters in batch mode\n\n Documentation/git-cat-file.txt |  40 +++++++++++----\n builtin/cat-file.c             | 110 ++++++++++++++++++++++++++++++++++++++---\n t/t8010-cat-file-filters.sh    |  64 ++++++++++++++++++++++++\n 3 files changed, 196 insertions(+), 18 deletions(-)\n create mode 100755 t/t8010-cat-file-filters.sh\n\nPublished-As: https://github.com/dscho/git/releases/tag/cat-file-filters-v3\nFetch-It-Via: git fetch https://github.com/dscho/git cat-file-filters-v3\n\nInterdiff vs v2:\n\n diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n index f8a3a08..4461153 100644\n --- a/builtin/cat-file.c\n +++ b/builtin/cat-file.c\n @@ -71,7 +71,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n  \n  \tif (!path)\n  \t\tpath = obj_context.path;\n -\telse if (obj_context.mode == S_IFINVALID)\n +\tif (obj_context.mode == S_IFINVALID)\n  \t\tobj_context.mode = 0100644;\n  \n  \tbuf = NULL;\n\n-- \n2.10.0.windows.1.10.g803177d\n\nbase-commit: 6ebdac1bab966b720d776aa43ca188fe378b1f4b\n"},{"id":"301473","messageId":"9e01395c0732b47b382d2363a2ef6f4bf361666e.1473415827.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1473415827.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T10:10:50Z","receivedAt":"2016-09-09T10:11:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There are circumstances when it is relatively easy to figure out the\nobject name for a given path, but not the name of the containing tree.\nFor example, when looking at a diff generated by Git, the object names\nare recorded, but not the revision. As a matter of fact, the revisions\nfrom which the diff was generated may not even exist locally.\n\nIn such a case, the user would have to generate a fake revision just to\nbe able to use --textconv or --filters.\n\nLet's simplify this dramatically, because we do not really need that\nrevision at all: all we care about is that we know the path. In the\nscenario described above, we do know the path, and we just want to\nspecify it separately from the object name.\n\nExample usage:\n\n\tgit cat-file --textconv --path=main.c 0f1937fd\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt |  7 ++++++-\n builtin/cat-file.c             | 26 +++++++++++++++++++++-----\n t/t8010-cat-file-filters.sh    | 20 ++++++++++++++++++++\n 3 files changed, 47 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 537d02c..4fa9041 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -9,7 +9,7 @@ git-cat-file - Provide content or type and size information for repository objec\n SYNOPSIS\n --------\n [verse]\n-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>\n 'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n \n DESCRIPTION\n@@ -64,6 +64,11 @@ OPTIONS\n \tend-of-line conversion, etc). In this case, <object> has to be of\n \tthe form <tree-ish>:<path>, or :<path>.\n \n+--path=<path>::\n+\tFor use with --textconv or --filters, to allow specifying an object\n+\tname and a path separately, e.g. when it is difficult to figure out\n+\tthe revision from which the blob came.\n+\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 0b74afa..b648056 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -20,6 +20,8 @@ struct batch_options {\n \tconst char *format;\n };\n \n+static const char *force_path;\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const unsigned char *sha1,\n \t\t\t char **buf, unsigned long *size)\n@@ -58,6 +60,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tstruct object_info oi = {NULL};\n \tstruct strbuf sb = STRBUF_INIT;\n \tunsigned flags = LOOKUP_REPLACE_OBJECT;\n+\tconst char *path = force_path;\n \n \tif (unknown_type)\n \t\tflags |= LOOKUP_UNKNOWN_OBJECT;\n@@ -65,6 +68,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tif (get_sha1_with_context(obj_name, 0, sha1, &obj_context))\n \t\tdie(\"Not a valid object name %s\", obj_name);\n \n+\tif (!path)\n+\t\tpath = obj_context.path;\n+\tif (obj_context.mode == S_IFINVALID)\n+\t\tobj_context.mode = 0100644;\n+\n \tbuf = NULL;\n \tswitch (opt) {\n \tcase 't':\n@@ -89,21 +97,22 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\treturn !has_sha1_file(sha1);\n \n \tcase 'w':\n-\t\tif (!obj_context.path[0])\n+\t\tif (!path[0])\n \t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n \t\t\t    \"<sha1:path>\", obj_name);\n \n-\t\tif (filter_object(obj_context.path, obj_context.mode,\n+\t\tif (filter_object(path, obj_context.mode,\n \t\t\t\t  sha1, &buf, &size))\n \t\t\treturn -1;\n \t\tbreak;\n \n \tcase 'c':\n-\t\tif (!obj_context.path[0])\n+\t\tif (!path[0])\n \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n \t\t\t    obj_name);\n \n-\t\tif (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))\n+\t\tif (textconv_object(path, obj_context.mode,\n+\t\t\t\t    sha1, 1, &buf, &size))\n \t\t\tbreak;\n \n \tcase 'p':\n@@ -477,7 +486,7 @@ static int batch_objects(struct batch_options *opt)\n }\n \n static const char * const cat_file_usage[] = {\n-\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) <object>\"),\n+\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>\"),\n \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n \tNULL\n };\n@@ -525,6 +534,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n \t\tOPT_CMDMODE(0, \"filters\", &opt,\n \t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n+\t\tOPT_STRING(0, \"path\", &force_path, N_(\"blob\"),\n+\t\t\t   N_(\"use a specific path for --textconv/--filters\")),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\n@@ -567,6 +578,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(cat_file_usage, options);\n \t}\n \n+\tif (force_path && opt != 'c' && opt != 'w') {\n+\t\terror(\"--path=<path> needs --textconv or --filters\");\n+\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\n \tif (batch.buffer_output < 0)\n \t\tbatch.buffer_output = batch.all_objects;\n \ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nindex e466634..0d5c33e 100755\n--- a/t/t8010-cat-file-filters.sh\n+++ b/t/t8010-cat-file-filters.sh\n@@ -31,4 +31,24 @@ test_expect_success 'cat-file --filters converts to worktree version' '\n \thas_cr actual\n '\n \n+test_expect_success 'cat-file --filters --path=<path> works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\tgit cat-file --filters --path=world.txt $sha1 >actual &&\n+\thas_cr actual\n+'\n+\n+test_expect_success 'cat-file --textconv --path=<path> works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n+\tgit cat-file --textconv --path=hello.txt $sha1 >rot13 &&\n+\ttest uryyb = \"$(cat rot13 | remove_cr)\"\n+'\n+\n+test_expect_success '----path=<path> complains without --textconv/--filters' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&\n+\ttest ! -s actual &&\n+\tgrep \"path.*needs.*filters\" err\n+'\n+\n test_done\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301474","messageId":"22debd2f58973cab5d0e1c9b7f1be4815004323a.1473415827.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1473415827.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 4/4] cat-file: support --textconv/--filters in batch mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T10:10:54Z","receivedAt":"2016-09-09T10:11:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"With this patch, --batch can be combined with --textconv or --filters.\nFor this to work, the input needs to have the form\n\n\t<object name><single white space><path>\n\nso that the filters can be chosen appropriately.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 18 +++++++++++-----\n builtin/cat-file.c             | 49 +++++++++++++++++++++++++++++++++++++-----\n t/t8010-cat-file-filters.sh    | 10 +++++++++\n 3 files changed, 67 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 4fa9041..204541c 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>\n-'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n+'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]\n \n DESCRIPTION\n -----------\n@@ -20,7 +20,11 @@ object type, or `-s` is used to find the object size, or `--textconv` or\n `--filters` is used (which imply type \"blob\").\n \n In the second form, a list of objects (separated by linefeeds) is provided on\n-stdin, and the SHA-1, type, and size of each object is printed on stdout.\n+stdin, and the SHA-1, type, and size of each object is printed on stdout. The\n+output format can be overridden using the optional `<format>` argument. If\n+either `--textconv` or `--filters` was specified, the input is expected to\n+list the object names followed by the path name, separated by a single white\n+space, so that the appropriate drivers can be determined.\n \n OPTIONS\n -------\n@@ -72,13 +76,17 @@ OPTIONS\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\n-\ton stdin.  May not be combined with any other options or arguments.\n-\tSee the section `BATCH OUTPUT` below for details.\n+\ton stdin.  May not be combined with any other options or arguments\n+\texcept `--textconv` or `--filters`, in which case the input lines\n+\talso need to specify the path, separated by white space.  See the\n+\tsection `BATCH OUTPUT` below for details.\n \n --batch-check::\n --batch-check=<format>::\n \tPrint object information for each object provided on stdin.  May\n-\tnot be combined with any other options or arguments.  See the\n+\tnot be combined with any other options or arguments except\n+\t`--textconv` or `--filters`, in which case the input lines also\n+\tneed to specify the path, separated by white space.  See the\n \tsection `BATCH OUTPUT` below for details.\n \n --batch-all-objects::\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex b648056..4461153 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -17,6 +17,7 @@ struct batch_options {\n \tint print_contents;\n \tint buffer_output;\n \tint all_objects;\n+\tint cmdmode; /* may be 'w' or 'c' for --filters or --textconv */\n \tconst char *format;\n };\n \n@@ -285,7 +286,32 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \tif (data->type == OBJ_BLOB) {\n \t\tif (opt->buffer_output)\n \t\t\tfflush(stdout);\n-\t\tif (stream_blob_to_fd(1, sha1, NULL, 0) < 0)\n+\t\tif (opt->cmdmode) {\n+\t\t\tchar *contents;\n+\t\t\tunsigned long size;\n+\n+\t\t\tif (!data->rest)\n+\t\t\t\tdie(\"missing path for '%s'\", sha1_to_hex(sha1));\n+\n+\t\t\tif (opt->cmdmode == 'w') {\n+\t\t\t\tif (filter_object(data->rest, 0100644, sha1,\n+\t\t\t\t\t\t  &contents, &size))\n+\t\t\t\t\tdie(\"could not convert '%s' %s\",\n+\t\t\t\t\t    sha1_to_hex(sha1), data->rest);\n+\t\t\t} else if (opt->cmdmode == 'c') {\n+\t\t\t\tenum object_type type;\n+\t\t\t\tif (!textconv_object(data->rest, 0100644, sha1,\n+\t\t\t\t\t\t     1, &contents, &size))\n+\t\t\t\t\tcontents = read_sha1_file(sha1, &type,\n+\t\t\t\t\t\t\t\t  &size);\n+\t\t\t\tif (!contents)\n+\t\t\t\t\tdie(\"could not convert '%s' %s\",\n+\t\t\t\t\t    sha1_to_hex(sha1), data->rest);\n+\t\t\t} else\n+\t\t\t\tdie(\"BUG: invalid cmdmode: %c\", opt->cmdmode);\n+\t\t\tbatch_write(opt, contents, size);\n+\t\t\tfree(contents);\n+\t\t} else if (stream_blob_to_fd(1, sha1, NULL, 0) < 0)\n \t\t\tdie(\"unable to stream %s to stdout\", sha1_to_hex(sha1));\n \t}\n \telse {\n@@ -422,6 +448,8 @@ static int batch_objects(struct batch_options *opt)\n \tdata.mark_query = 1;\n \tstrbuf_expand(&buf, opt->format, expand_format, &data);\n \tdata.mark_query = 0;\n+\tif (opt->cmdmode)\n+\t\tdata.split_on_whitespace = 1;\n \n \tif (opt->all_objects) {\n \t\tstruct object_info empty;\n@@ -487,7 +515,7 @@ static int batch_objects(struct batch_options *opt)\n \n static const char * const cat_file_usage[] = {\n \tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) [--path=<path>] <object>\"),\n-\tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n+\tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv|--filters]\"),\n \tNULL\n };\n \n@@ -558,7 +586,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);\n \n \tif (opt) {\n-\t\tif (argc == 1)\n+\t\tif (batch.enabled && (opt == 'c' || opt == 'w'))\n+\t\t\tbatch.cmdmode = opt;\n+\t\telse if (argc == 1)\n \t\t\tobj_name = argv[0];\n \t\telse\n \t\t\tusage_with_options(cat_file_usage, options);\n@@ -570,8 +600,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\t} else\n \t\t\tusage_with_options(cat_file_usage, options);\n \t}\n-\tif (batch.enabled && (opt || argc)) {\n-\t\tusage_with_options(cat_file_usage, options);\n+\tif (batch.enabled) {\n+\t\tif (batch.cmdmode != opt || argc)\n+\t\t\tusage_with_options(cat_file_usage, options);\n+\t\tif (batch.cmdmode && batch.all_objects)\n+\t\t\tdie(\"--batch-all-objects cannot be combined with \"\n+\t\t\t    \"--textconv nor with --filters\");\n \t}\n \n \tif ((batch.follow_symlinks || batch.all_objects) && !batch.enabled) {\n@@ -583,6 +617,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(cat_file_usage, options);\n \t}\n \n+\tif (force_path && batch.enabled) {\n+\t\terror(\"--path=<path> incompatible with --batch\");\n+\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\n \tif (batch.buffer_output < 0)\n \t\tbatch.buffer_output = batch.all_objects;\n \ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nindex 0d5c33e..acdfa09 100755\n--- a/t/t8010-cat-file-filters.sh\n+++ b/t/t8010-cat-file-filters.sh\n@@ -51,4 +51,14 @@ test_expect_success '----path=<path> complains without --textconv/--filters' '\n \tgrep \"path.*needs.*filters\" err\n '\n \n+test_expect_success 'cat-file --textconv --batch works' '\n+\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n+\ttest_config diff.txt.textconv \"tr A-Za-z N-ZA-Mn-za-m <\" &&\n+\tprintf \"%s hello.txt\\n%s hello\\n\" $sha1 $sha1 |\n+\tgit cat-file --textconv --batch >actual &&\n+\tprintf \"%s blob 6\\nuryyb\\r\\n\\n%s blob 6\\nhello\\n\\n\" \\\n+\t\t$sha1 $sha1 >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.10.0.windows.1.10.g803177d\n"},{"id":"301475","messageId":"084088ba86c0af3636d960276c0bfdf7f5d2cfde.1473415827.git.johannes.schindelin@gmx.de","threadId":"43877","inReplyTo":"cover.1473415827.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T10:10:47Z","receivedAt":"2016-09-09T10:11:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The --filters option applies the convert_to_working_tree() filter for\nthe path when showing the contents of a regular file blob object.\n\nThis feature comes in handy when a 3rd-party tool wants to work with\nthe contents of files from past revisions as if they had been checked\nout, but without detouring via temporary files.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-cat-file.txt | 12 +++++++++---\n builtin/cat-file.c             | 41 ++++++++++++++++++++++++++++++++++++++++-\n t/t8010-cat-file-filters.sh    | 34 ++++++++++++++++++++++++++++++++++\n 3 files changed, 83 insertions(+), 4 deletions(-)\n create mode 100755 t/t8010-cat-file-filters.sh\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 071029b..537d02c 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -9,15 +9,15 @@ git-cat-file - Provide content or type and size information for repository objec\n SYNOPSIS\n --------\n [verse]\n-'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv ) <object>\n+'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>\n 'git cat-file' (--batch | --batch-check) [--follow-symlinks]\n \n DESCRIPTION\n -----------\n In its first form, the command provides the content or the type of an object in\n the repository. The type is required unless `-t` or `-p` is used to find the\n-object type, or `-s` is used to find the object size, or `--textconv` is used\n-(which implies type \"blob\").\n+object type, or `-s` is used to find the object size, or `--textconv` or\n+`--filters` is used (which imply type \"blob\").\n \n In the second form, a list of objects (separated by linefeeds) is provided on\n stdin, and the SHA-1, type, and size of each object is printed on stdout.\n@@ -58,6 +58,12 @@ OPTIONS\n \torder to apply the filter to the content recorded in the index at\n \t<path>.\n \n+--filters::\n+\tShow the content as converted by the filters configured in\n+\tthe current working tree for the given <path> (i.e. smudge filters,\n+\tend-of-line conversion, etc). In this case, <object> has to be of\n+\tthe form <tree-ish>:<path>, or :<path>.\n+\n --batch::\n --batch=<format>::\n \tPrint object information and contents for each object provided\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 2dfe626..0b74afa 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -20,6 +20,33 @@ struct batch_options {\n \tconst char *format;\n };\n \n+static int filter_object(const char *path, unsigned mode,\n+\t\t\t const unsigned char *sha1,\n+\t\t\t char **buf, unsigned long *size)\n+{\n+\tenum object_type type;\n+\n+\t*buf = read_sha1_file(sha1, &type, size);\n+\tif (!*buf)\n+\t\treturn error(_(\"cannot read object %s '%s'\"),\n+\t\t\tsha1_to_hex(sha1), path);\n+\tif (type != OBJ_BLOB) {\n+\t\tfree(*buf);\n+\t\treturn error(_(\"blob expected for %s '%s'\"),\n+\t\t\tsha1_to_hex(sha1), path);\n+\t}\n+\tif (S_ISREG(mode)) {\n+\t\tstruct strbuf strbuf = STRBUF_INIT;\n+\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n+\t\t\tfree(*buf);\n+\t\t\t*size = strbuf.len;\n+\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t\tint unknown_type)\n {\n@@ -61,6 +88,16 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \tcase 'e':\n \t\treturn !has_sha1_file(sha1);\n \n+\tcase 'w':\n+\t\tif (!obj_context.path[0])\n+\t\t\tdie(\"git cat-file --filters %s: <object> must be \"\n+\t\t\t    \"<sha1:path>\", obj_name);\n+\n+\t\tif (filter_object(obj_context.path, obj_context.mode,\n+\t\t\t\t  sha1, &buf, &size))\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n \tcase 'c':\n \t\tif (!obj_context.path[0])\n \t\t\tdie(\"git cat-file --textconv %s: <object> must be <sha1:path>\",\n@@ -440,7 +477,7 @@ static int batch_objects(struct batch_options *opt)\n }\n \n static const char * const cat_file_usage[] = {\n-\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv) <object>\"),\n+\tN_(\"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--filters) <object>\"),\n \tN_(\"git cat-file (--batch | --batch-check) [--follow-symlinks]\"),\n \tNULL\n };\n@@ -486,6 +523,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('p', NULL, &opt, N_(\"pretty-print object's content\"), 'p'),\n \t\tOPT_CMDMODE(0, \"textconv\", &opt,\n \t\t\t    N_(\"for blob objects, run textconv on object's content\"), 'c'),\n+\t\tOPT_CMDMODE(0, \"filters\", &opt,\n+\t\t\t    N_(\"for blob objects, run filters on object's content\"), 'w'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\ndiff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh\nnew file mode 100755\nindex 0000000..e466634\n--- /dev/null\n+++ b/t/t8010-cat-file-filters.sh\n@@ -0,0 +1,34 @@\n+#!/bin/sh\n+\n+test_description='git cat-file filters support'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup ' '\n+\techo \"*.txt eol=crlf diff=txt\" >.gitattributes &&\n+\techo \"hello\" | append_cr >world.txt &&\n+\tgit add .gitattributes world.txt &&\n+\ttest_tick &&\n+\tgit commit -m \"Initial commit\"\n+'\n+\n+has_cr () {\n+\ttr '\\015' Q <\"$1\" | grep Q >/dev/null\n+}\n+\n+test_expect_success 'no filters with `git show`' '\n+\tgit show HEAD:world.txt >actual &&\n+\t! has_cr actual\n+\n+'\n+\n+test_expect_success 'no filters with cat-file' '\n+\tgit cat-file blob HEAD:world.txt >actual &&\n+\t! has_cr actual\n+'\n+\n+test_expect_success 'cat-file --filters converts to worktree version' '\n+\tgit cat-file --filters HEAD:world.txt >actual &&\n+\thas_cr actual\n+'\n+\n+test_done\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301515","messageId":"xmqqfup9ds9p.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"084088ba86c0af3636d960276c0bfdf7f5d2cfde.1473415827.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-09T15:09:22Z","receivedAt":"2016-09-09T15:09:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> +static int filter_object(const char *path, unsigned mode,\n> +\t\t\t const unsigned char *sha1,\n> +\t\t\t char **buf, unsigned long *size)\n> +{\n> +\tenum object_type type;\n> +\n> +\t*buf = read_sha1_file(sha1, &type, size);\n> +\tif (!*buf)\n> +\t\treturn error(_(\"cannot read object %s '%s'\"),\n> +\t\t\tsha1_to_hex(sha1), path);\n> +\tif (type != OBJ_BLOB) {\n> +\t\tfree(*buf);\n> +\t\treturn error(_(\"blob expected for %s '%s'\"),\n> +\t\t\tsha1_to_hex(sha1), path);\n> +\t}\n> +\tif (S_ISREG(mode)) {\n> +\t\tstruct strbuf strbuf = STRBUF_INIT;\n> +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n> +\t\t\tfree(*buf);\n> +\t\t\t*size = strbuf.len;\n> +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n> +\t\t}\n> +\t}\n\nThis needs to error out when mode is not ISREG just like it errors\nout when type is not BLOB.\n\nOther than that, I think these four patches are good to go.\n\nThanks.\n"},{"id":"301518","messageId":"alpine.DEB.2.20.1609091800020.129229@virtualbox","threadId":"43877","inReplyTo":"xmqqfup9ds9p.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T16:01:21Z","receivedAt":"2016-09-09T16:01:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 9 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > +static int filter_object(const char *path, unsigned mode,\n> > +\t\t\t const unsigned char *sha1,\n> > +\t\t\t char **buf, unsigned long *size)\n> > +{\n> > +\tenum object_type type;\n> > +\n> > +\t*buf = read_sha1_file(sha1, &type, size);\n> > +\tif (!*buf)\n> > +\t\treturn error(_(\"cannot read object %s '%s'\"),\n> > +\t\t\tsha1_to_hex(sha1), path);\n> > +\tif (type != OBJ_BLOB) {\n> > +\t\tfree(*buf);\n> > +\t\treturn error(_(\"blob expected for %s '%s'\"),\n> > +\t\t\tsha1_to_hex(sha1), path);\n> > +\t}\n> > +\tif (S_ISREG(mode)) {\n> > +\t\tstruct strbuf strbuf = STRBUF_INIT;\n> > +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n> > +\t\t\tfree(*buf);\n> > +\t\t\t*size = strbuf.len;\n> > +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n> > +\t\t}\n> > +\t}\n> \n> This needs to error out when mode is not ISREG just like it errors\n> out when type is not BLOB.\n\nAre you sure that this is desirable in batch mode?\n\nCiao,\nDscho\n"},{"id":"301519","messageId":"xmqqbmzxdpjp.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1609091800020.129229@virtualbox","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-09T16:08:10Z","receivedAt":"2016-09-09T16:08:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > +\tif (type != OBJ_BLOB) {\n>> > +\t\tfree(*buf);\n>> > +\t\treturn error(_(\"blob expected for %s '%s'\"),\n>> > +\t\t\tsha1_to_hex(sha1), path);\n>> > +\t}\n>> > +\tif (S_ISREG(mode)) {\n>> > +\t\tstruct strbuf strbuf = STRBUF_INIT;\n>> > +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n>> > +\t\t\tfree(*buf);\n>> > +\t\t\t*size = strbuf.len;\n>> > +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n>> > +\t\t}\n>> > +\t}\n>> \n>> This needs to error out when mode is not ISREG just like it errors\n>> out when type is not BLOB.\n>\n> Are you sure that this is desirable in batch mode?\n\nI do not quite see a reason why we should not diagnose a bad input\nthat does not produce a filtered result.  In batch mode or not, it\ndiagnoses when the user feeds it a non-blob, and I think it should\ndo so for non-regular, too. Both are \"you asked me to filter, but\nyou shouldn't have\".\n\n\n\n"},{"id":"301526","messageId":"xmqqvay5c7t3.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"xmqqbmzxdpjp.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-09T17:16:40Z","receivedAt":"2016-09-09T17:16:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>\n>>> > +\tif (type != OBJ_BLOB) {\n>>> > +\t\tfree(*buf);\n>>> > +\t\treturn error(_(\"blob expected for %s '%s'\"),\n>>> > +\t\t\tsha1_to_hex(sha1), path);\n>>> > +\t}\n>>> > +\tif (S_ISREG(mode)) {\n>>> > +\t\tstruct strbuf strbuf = STRBUF_INIT;\n>>> > +\t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n>>> > +\t\t\tfree(*buf);\n>>> > +\t\t\t*size = strbuf.len;\n>>> > +\t\t\t*buf = strbuf_detach(&strbuf, NULL);\n>>> > +\t\t}\n>>> > +\t}\n>>> \n>>> This needs to error out when mode is not ISREG just like it errors\n>>> out when type is not BLOB.\n>>\n>> Are you sure that this is desirable in batch mode?\n>\n> I do not quite see a reason why we should not diagnose a bad input\n> that does not produce a filtered result.  In batch mode or not, it\n> diagnoses when the user feeds it a non-blob, and I think it should\n> do so for non-regular, too. Both are \"you asked me to filter, but\n> you shouldn't have\".\n\nStepping back a bit, I can also see a use case that would be helped\nif this filter_object() function by default gives the contents of\nthe requested object as-is, unless the object is a regular blob with\na path for which filtering is defined.  Driving such a mechanism via\nthe batch interface will allow you to first ask about the top-level\ntree object (given back to you as-is), and you can iterate over its\nentries recursively and get the blobs to be placed in a new working\ndirectory (i.e. \"git archive\" piped to \"tar xf\" but regular files\nare passed thru convert_to_working_tree()).  In such an application,\nafter you learn the mode from the containing tree object and know\nthat RelNotes is a symbolic link blob, you still would want the\ncontents out of the pipe going to the same batch interface process\nthat is not filtered.\n\nSo I would not mind if we define the semantics of \"--filters\" as\nsuch (as long as it is clearly documented, of course).  AFAICS, the\nbatch interface does not call filter_object() for non-blobs, and by\nreturning successfully without doing anything special for a symbolic\nlink from filter_object() automatically gives us the \"by default\nreturn as-is, but give processed output only for regular file blobs\"\nsemantics to the batch mode.\n\nBut for a non-batch mode, it feels somewhat funny to be giving the\nas-is output without saying anything to symbolic links; we can argue\nthat it is being consistent with what we do in the batch mode,\nthough.\n\nThanks.\n"},{"id":"301527","messageId":"xmqqr38tc7d1.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"xmqqvay5c7t3.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-09T17:26:18Z","receivedAt":"2016-09-09T17:26:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> So I would not mind if we define the semantics of \"--filters\" as\n> such (as long as it is clearly documented, of course).  AFAICS, the\n> batch interface does not call filter_object() for non-blobs, and by\n> returning successfully without doing anything special for a symbolic\n> link from filter_object() automatically gives us the \"by default\n> return as-is, but give processed output only for regular file blobs\"\n> semantics to the batch mode.\n>\n> But for a non-batch mode, it feels somewhat funny to be giving the\n> as-is output without saying anything to symbolic links; we can argue\n> that it is being consistent with what we do in the batch mode,\n> though.\n\nIn other words, instead of trying to be consistent by erroring out\nin non-regular blob case, I think the attached change on top would\nmake more sense, by consistently passing the object contents as-is\nfor all \"not filtered\" cases, whether it is run from the batch mode\nor from the command line.\n\n builtin/cat-file.c | 7 +------\n 1 file changed, 1 insertion(+), 6 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex f8a3a08..99cb525 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -33,12 +33,7 @@ static int filter_object(const char *path, unsigned mode,\n \tif (!*buf)\n \t\treturn error(_(\"cannot read object %s '%s'\"),\n \t\t\tsha1_to_hex(sha1), path);\n-\tif (type != OBJ_BLOB) {\n-\t\tfree(*buf);\n-\t\treturn error(_(\"blob expected for %s '%s'\"),\n-\t\t\tsha1_to_hex(sha1), path);\n-\t}\n-\tif (S_ISREG(mode)) {\n+\tif ((type == OBJ_BLOB) && S_ISREG(mode)) {\n \t\tstruct strbuf strbuf = STRBUF_INIT;\n \t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n \t\t\tfree(*buf);\n"},{"id":"301536","messageId":"xmqq4m5pc5hx.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"9e01395c0732b47b382d2363a2ef6f4bf361666e.1473415827.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-09T18:06:34Z","receivedAt":"2016-09-09T18:06:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> +test_expect_success '----path=<path> complains without --textconv/--filters' '\n\nI wonder where this \"----path\" came from; it wasn't in v2 I queued,\nbut somehow came back mysteriously.\n\nWill locally amend.\n\n> +\tsha1=$(git rev-parse -q --verify HEAD:world.txt) &&\n> +\ttest_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&\n> +\ttest ! -s actual &&\n> +\tgrep \"path.*needs.*filters\" err\n> +'\n> +\n>  test_done\n"},{"id":"301592","messageId":"alpine.DEB.2.20.1609100957040.129229@virtualbox","threadId":"43877","inReplyTo":"xmqqr38tc7d1.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-10T07:57:33Z","receivedAt":"2016-09-10T07:57:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 9 Sep 2016, Junio C Hamano wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > So I would not mind if we define the semantics of \"--filters\" as\n> > such (as long as it is clearly documented, of course).  AFAICS, the\n> > batch interface does not call filter_object() for non-blobs, and by\n> > returning successfully without doing anything special for a symbolic\n> > link from filter_object() automatically gives us the \"by default\n> > return as-is, but give processed output only for regular file blobs\"\n> > semantics to the batch mode.\n> >\n> > But for a non-batch mode, it feels somewhat funny to be giving the\n> > as-is output without saying anything to symbolic links; we can argue\n> > that it is being consistent with what we do in the batch mode,\n> > though.\n> \n> In other words, instead of trying to be consistent by erroring out\n> in non-regular blob case, I think the attached change on top would\n> make more sense, by consistently passing the object contents as-is\n> for all \"not filtered\" cases, whether it is run from the batch mode\n> or from the command line.\n> \n>  builtin/cat-file.c | 7 +------\n>  1 file changed, 1 insertion(+), 6 deletions(-)\n> \n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index f8a3a08..99cb525 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -33,12 +33,7 @@ static int filter_object(const char *path, unsigned mode,\n>  \tif (!*buf)\n>  \t\treturn error(_(\"cannot read object %s '%s'\"),\n>  \t\t\tsha1_to_hex(sha1), path);\n> -\tif (type != OBJ_BLOB) {\n> -\t\tfree(*buf);\n> -\t\treturn error(_(\"blob expected for %s '%s'\"),\n> -\t\t\tsha1_to_hex(sha1), path);\n> -\t}\n> -\tif (S_ISREG(mode)) {\n> +\tif ((type == OBJ_BLOB) && S_ISREG(mode)) {\n>  \t\tstruct strbuf strbuf = STRBUF_INIT;\n>  \t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n>  \t\t\tfree(*buf);\n\nYes, that makes most sense to me, too.\n\nCiao,\nDscho\n"},{"id":"301593","messageId":"alpine.DEB.2.20.1609100958160.129229@virtualbox","threadId":"43877","inReplyTo":"xmqq4m5pc5hx.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 3/4] cat-file --textconv/--filters: allow specifying the path separately","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-10T07:59:01Z","receivedAt":"2016-09-10T07:59:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 9 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > +test_expect_success '----path=<path> complains without --textconv/--filters' '\n> \n> I wonder where this \"----path\" came from; it wasn't in v2 I queued,\n> but somehow came back mysteriously.\n\nNo idea how it crept back in. Sorry.\n\n> Will locally amend.\n\nThanks!\nDscho\n"},{"id":"301670","messageId":"xmqqzine6rhs.fsf@gitster.mtv.corp.google.com","threadId":"43877","inReplyTo":"alpine.DEB.2.20.1609100957040.129229@virtualbox","subject":"Re: [PATCH v3 2/4] cat-file: introduce the --filters option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-11T21:44:47Z","receivedAt":"2016-09-11T21:44:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> In other words, instead of trying to be consistent by erroring out\n>> in non-regular blob case, I think the attached change on top would\n>> make more sense, by consistently passing the object contents as-is\n>> for all \"not filtered\" cases, whether it is run from the batch mode\n>> or from the command line.\n>>  ...\n>> +\tif ((type == OBJ_BLOB) && S_ISREG(mode)) {\n>>  \t\tstruct strbuf strbuf = STRBUF_INIT;\n>>  \t\tif (convert_to_working_tree(path, *buf, *size, &strbuf)) {\n>>  \t\t\tfree(*buf);\n>\n> Yes, that makes most sense to me, too.\n\nAlright; will squash it in then before merging it down to 'next'.\n\n\n"}]}