Skip to content

Commit a918477

Browse files
committed
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 0f1937f Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 0f84484 commit a918477

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

Documentation/git-cat-file.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-cat-file - Provide content or type and size information for repository objec
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --smudge ) <object>
12+
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --smudge ) [--use-path=<path>] <object>
1313
'git cat-file' (--batch | --batch-check) [--follow-symlinks]
1414

1515
DESCRIPTION
@@ -63,6 +63,11 @@ OPTIONS
6363
the current working tree for the given <path>. In this case,
6464
<object> has to be of the form <tree-ish>:<path>, or :<path>.
6565

66+
--use-path=<path>::
67+
For use with --textconv or --smudge, to allow specifying an object
68+
name and a path separately, e.g. when it is difficult to figure out
69+
the revision from which the blob came.
70+
6671
--batch::
6772
--batch=<format>::
6873
Print object information and contents for each object provided

builtin/cat-file.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ struct batch_options {
2020
const char *format;
2121
};
2222

23+
static const char *force_path;
24+
2325
static int smudge_object(const char *path, unsigned mode, unsigned char *sha1,
2426
char **buf, unsigned long *size)
2527
{
@@ -88,20 +90,24 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
8890
return !has_sha1_file(sha1);
8991

9092
case 'w':
91-
if (!obj_context.path[0])
93+
if (!force_path && !obj_context.path[0])
9294
die("git cat-file --smudge %s: <object> must be <sha1:path>",
9395
obj_name);
9496

95-
if (smudge_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
97+
if (smudge_object(force_path ? force_path : obj_context.path,
98+
force_path ? 0100644 : obj_context.mode,
99+
sha1, &buf, &size))
96100
return -1;
97101
break;
98102

99103
case 'c':
100-
if (!obj_context.path[0])
104+
if (!force_path && !obj_context.path[0])
101105
die("git cat-file --textconv %s: <object> must be <sha1:path>",
102106
obj_name);
103107

104-
if (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
108+
if (textconv_object(force_path ? force_path : obj_context.path,
109+
force_path ? 0100644 : obj_context.mode,
110+
sha1, 1, &buf, &size))
105111
break;
106112

107113
case 'p':
@@ -475,7 +481,7 @@ static int batch_objects(struct batch_options *opt)
475481
}
476482

477483
static const char * const cat_file_usage[] = {
478-
N_("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--smudge) <object>"),
484+
N_("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv|--smudge) [--use-path=<path>] <object>"),
479485
N_("git cat-file (--batch | --batch-check) [--follow-symlinks]"),
480486
NULL
481487
};
@@ -523,6 +529,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
523529
N_("for blob objects, run textconv on object's content"), 'c'),
524530
OPT_CMDMODE(0, "smudge", &opt,
525531
N_("for blob objects, run smudge filters on object's content"), 'w'),
532+
OPT_STRING(0, "use-path", &force_path, N_("blob"),
533+
N_("use a specific path for --textconv/--smudge")),
526534
OPT_BOOL(0, "allow-unknown-type", &unknown_type,
527535
N_("allow -s and -t to work with broken/corrupt objects")),
528536
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)
565573
usage_with_options(cat_file_usage, options);
566574
}
567575

576+
if (force_path && opt != 'c' && opt != 'w') {
577+
error("--use-path=<path> needs --textconv or --smudge");
578+
usage_with_options(cat_file_usage, options);
579+
}
580+
568581
if (batch.buffer_output < 0)
569582
batch.buffer_output = batch.all_objects;
570583

t/t8010-cat-file-filters.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ test_description='git cat-file filters support'
44
. ./test-lib.sh
55

66
test_expect_success 'setup ' '
7-
echo "*.txt eol=crlf" >.gitattributes &&
7+
echo "*.txt eol=crlf diff=txt" >.gitattributes &&
88
echo "hello" | append_cr >world.txt &&
99
git add .gitattributes world.txt &&
1010
test_tick &&
@@ -31,4 +31,17 @@ test_expect_success 'cat-file --smudge converts to worktree version' '
3131
has_cr actual
3232
'
3333

34+
test_expect_success 'cat-file --smudge --use-path=<path> works' '
35+
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
36+
git cat-file --smudge --use-path=world.txt $sha1 >actual &&
37+
has_cr actual
38+
'
39+
40+
test_expect_success 'cat-file --textconv --use-path=<path> works' '
41+
sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
42+
test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" &&
43+
git cat-file --textconv --use-path=hello.txt $sha1 >rot13 &&
44+
test uryyb = "$(cat rot13)"
45+
'
46+
3447
test_done

0 commit comments

Comments
 (0)