Skip to content

Commit

Permalink
cat-file --textconv/--filters: allow specifying the path separately
Browse files Browse the repository at this point in the history
There are circumstances when it is relatively easy to figure out the
object name for a given path, but not the name of the containing tree.
For example, when looking at a diff generated by Git, the object names
are recorded, but not the revision. As a matter of fact, the revisions
from which the diff was generated may not even exist locally.

In such a case, the user would have to generate a fake revision just to
be able to use --textconv or --filters.

Let's simplify this dramatically, because we do not really need that
revision at all: all we care about is that we know the path. In the
scenario described above, we do know the path, and we just want to
specify it separately from the object name.

Example usage:

	git cat-file --textconv --path=main.c 0f1937fd

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
dscho authored and gitster committed Sep 11, 2016
1 parent b9e62f6 commit 7bcf341
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
7 changes: 6 additions & 1 deletion Documentation/git-cat-file.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ git-cat-file - Provide content or type and size information for repository objec
SYNOPSIS
--------
[verse]
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) <object>
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>
'git cat-file' (--batch | --batch-check) [--follow-symlinks]

DESCRIPTION
Expand Down Expand Up @@ -64,6 +64,11 @@ OPTIONS
end-of-line conversion, etc). In this case, <object> has to be of
the form <tree-ish>:<path>, or :<path>.

--path=<path>::
For use with --textconv or --filters, to allow specifying an object
name and a path separately, e.g. when it is difficult to figure out
the revision from which the blob came.

--batch::
--batch=<format>::
Print object information and contents for each object provided
Expand Down
26 changes: 21 additions & 5 deletions builtin/cat-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ struct batch_options {
const char *format;
};

static const char *force_path;

static int filter_object(const char *path, unsigned mode,
const unsigned char *sha1,
char **buf, unsigned long *size)
Expand Down Expand Up @@ -53,13 +55,19 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
struct object_info oi = {NULL};
struct strbuf sb = STRBUF_INIT;
unsigned flags = LOOKUP_REPLACE_OBJECT;
const char *path = force_path;

if (unknown_type)
flags |= LOOKUP_UNKNOWN_OBJECT;

if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
die("Not a valid object name %s", obj_name);

if (!path)
path = obj_context.path;
if (obj_context.mode == S_IFINVALID)
obj_context.mode = 0100644;

buf = NULL;
switch (opt) {
case 't':
Expand All @@ -84,21 +92,22 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
return !has_sha1_file(sha1);

case 'w':
if (!obj_context.path[0])
if (!path[0])
die("git cat-file --filters %s: <object> must be "
"<sha1:path>", obj_name);

if (filter_object(obj_context.path, obj_context.mode,
if (filter_object(path, obj_context.mode,
sha1, &buf, &size))
return -1;
break;

case 'c':
if (!obj_context.path[0])
if (!path[0])
die("git cat-file --textconv %s: <object> must be <sha1:path>",
obj_name);

if (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
if (textconv_object(path, obj_context.mode,
sha1, 1, &buf, &size))
break;

case 'p':
Expand Down Expand Up @@ -472,7 +481,7 @@ static int batch_objects(struct batch_options *opt)
}

static const char * const cat_file_usage[] = {
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]"),
NULL
};
Expand Down Expand Up @@ -520,6 +529,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("for blob objects, run textconv on object's content"), 'c'),
OPT_CMDMODE(0, "filters", &opt,
N_("for blob objects, run filters on object's content"), 'w'),
OPT_STRING(0, "path", &force_path, N_("blob"),
N_("use a specific path for --textconv/--filters")),
OPT_BOOL(0, "allow-unknown-type", &unknown_type,
N_("allow -s and -t to work with broken/corrupt objects")),
OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")),
Expand Down Expand Up @@ -562,6 +573,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
usage_with_options(cat_file_usage, options);
}

if (force_path && opt != 'c' && opt != 'w') {
error("--path=<path> needs --textconv or --filters");
usage_with_options(cat_file_usage, options);
}

if (batch.buffer_output < 0)
batch.buffer_output = batch.all_objects;

Expand Down
20 changes: 20 additions & 0 deletions t/t8010-cat-file-filters.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,24 @@ test_expect_success 'cat-file --filters converts to worktree version' '
has_cr actual
'

test_expect_success 'cat-file --filters --path=<path> works' '
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
git cat-file --filters --path=world.txt $sha1 >actual &&
has_cr actual
'

test_expect_success 'cat-file --textconv --path=<path> works' '
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" &&
git cat-file --textconv --path=hello.txt $sha1 >rot13 &&
test uryyb = "$(cat rot13 | remove_cr)"
'

test_expect_success '--path=<path> complains without --textconv/--filters' '
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
test_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&
test ! -s actual &&
grep "path.*needs.*filters" err
'

test_done

0 comments on commit 7bcf341

Please sign in to comment.