cat-file --textconv/--smudge: allow specifying the path separately

There are circumstances when it is relatively easy to figure out the
object name for a given path, but not the revision. 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 --smudge.

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 --use-path=main.c 0f1937fd

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2016-08-12 15:22:55 +02:00
parent 0f84484394
commit a918477ee2
3 changed files with 38 additions and 7 deletions

View File

@@ -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 | --smudge ) <object>
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --smudge ) [--use-path=<path>] <object>
'git cat-file' (--batch | --batch-check) [--follow-symlinks]
DESCRIPTION
@@ -63,6 +63,11 @@ OPTIONS
the current working tree for the given <path>. In this case,
<object> has to be of the form <tree-ish>:<path>, or :<path>.
--use-path=<path>::
For use with --textconv or --smudge, 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

View File

@@ -20,6 +20,8 @@ struct batch_options {
const char *format;
};
static const char *force_path;
static int smudge_object(const char *path, unsigned mode, unsigned char *sha1,
char **buf, unsigned long *size)
{
@@ -88,20 +90,24 @@ 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 (!force_path && !obj_context.path[0])
die("git cat-file --smudge %s: <object> must be <sha1:path>",
obj_name);
if (smudge_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
if (smudge_object(force_path ? force_path : obj_context.path,
force_path ? 0100644 : obj_context.mode,
sha1, &buf, &size))
return -1;
break;
case 'c':
if (!obj_context.path[0])
if (!force_path && !obj_context.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(force_path ? force_path : obj_context.path,
force_path ? 0100644 : obj_context.mode,
sha1, 1, &buf, &size))
break;
case 'p':
@@ -475,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|--smudge) <object>"),
N_("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--smudge) [--use-path=<path>] <object>"),
N_("git cat-file (--batch | --batch-check) [--follow-symlinks]"),
NULL
};
@@ -523,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, "smudge", &opt,
N_("for blob objects, run smudge filters on object's content"), 'w'),
OPT_STRING(0, "use-path", &force_path, N_("blob"),
N_("use a specific path for --textconv/--smudge")),
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")),
@@ -565,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("--use-path=<path> needs --textconv or --smudge");
usage_with_options(cat_file_usage, options);
}
if (batch.buffer_output < 0)
batch.buffer_output = batch.all_objects;

View File

@@ -4,7 +4,7 @@ test_description='git cat-file filters support'
. ./test-lib.sh
test_expect_success 'setup ' '
echo "*.txt eol=crlf" >.gitattributes &&
echo "*.txt eol=crlf diff=txt" >.gitattributes &&
echo "hello" | append_cr >world.txt &&
git add .gitattributes world.txt &&
test_tick &&
@@ -31,4 +31,17 @@ test_expect_success 'cat-file --smudge converts to worktree version' '
has_cr actual
'
test_expect_success 'cat-file --smudge --use-path=<path> works' '
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
git cat-file --smudge --use-path=world.txt $sha1 >actual &&
has_cr actual
'
test_expect_success 'cat-file --textconv --use-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 --use-path=hello.txt $sha1 >rot13 &&
test uryyb = "$(cat rot13)"
'
test_done