Skip to content

Commit 85c6239

Browse files
barrbraingitster
authored andcommitted
fast-import: let importers retrieve blobs
New objects written by fast-import are not available immediately. Until a checkpoint has been started and finishes writing the pack index, any new blobs will not be accessible using standard git tools. So introduce a new way to access them: a "cat-blob" command in the command stream requests for fast-import to print a blob to stdout or a file descriptor specified by the argument to --cat-blob-fd. The value for cat-blob-fd cannot be specified in the stream because that would be a layering violation: the decision of where to direct a stream has to be made when fast-import is started anyway, so we might as well make the stream format is independent of that detail. Output uses the same format as "git cat-file --batch". Thanks to Sverre Rabbelier and Sam Vilain for guidance in designing the protocol. Based-on-patch-by: Jonathan Nieder <[email protected]> Signed-off-by: David Barr <[email protected]> Acked-by: Ramkumar Ramachandra <[email protected]> Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4980fff commit 85c6239

File tree

3 files changed

+329
-2
lines changed

3 files changed

+329
-2
lines changed

Documentation/git-fast-import.txt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ OPTIONS
9292
--(no-)-relative-marks= with the --(import|export)-marks=
9393
options.
9494

95+
--cat-blob-fd=<fd>::
96+
Specify the file descriptor that will be written to
97+
when the `cat-blob` command is encountered in the stream.
98+
The default behaviour is to write to `stdout`.
99+
95100
--export-pack-edges=<file>::
96101
After creating a packfile, print a line of data to
97102
<file> listing the filename of the packfile and the last
@@ -320,6 +325,11 @@ and control the current import process. More detailed discussion
320325
standard output. This command is optional and is not needed
321326
to perform an import.
322327

328+
`cat-blob`::
329+
Causes fast-import to print a blob in 'cat-file --batch'
330+
format to the file descriptor set with `--cat-blob-fd` or
331+
`stdout` if unspecified.
332+
323333
`feature`::
324334
Require that fast-import supports the specified feature, or
325335
abort if it does not.
@@ -879,6 +889,29 @@ Placing a `progress` command immediately after a `checkpoint` will
879889
inform the reader when the `checkpoint` has been completed and it
880890
can safely access the refs that fast-import updated.
881891

892+
`cat-blob`
893+
~~~~~~~~~~
894+
Causes fast-import to print a blob to a file descriptor previously
895+
arranged with the `--cat-blob-fd` argument. The command otherwise
896+
has no impact on the current import; its main purpose is to
897+
retrieve blobs that may be in fast-import's memory but not
898+
accessible from the target repository.
899+
900+
....
901+
'cat-blob' SP <dataref> LF
902+
....
903+
904+
The `<dataref>` can be either a mark reference (`:<idnum>`)
905+
set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
906+
ready to be written.
907+
908+
output uses the same format as `git cat-file --batch`:
909+
910+
====
911+
<sha1> SP 'blob' SP <size> LF
912+
<contents> LF
913+
====
914+
882915
`feature`
883916
~~~~~~~~~
884917
Require that fast-import supports the specified feature, or abort if
@@ -905,6 +938,13 @@ import-marks::
905938
second, an --import-marks= command-line option overrides
906939
any "feature import-marks" command in the stream.
907940

941+
cat-blob::
942+
Ignored. Versions of fast-import not supporting the
943+
"cat-blob" command will exit with a message indicating so.
944+
This lets the import error out early with a clear message,
945+
rather than wasting time on the early part of an import
946+
before the unsupported command is detected.
947+
908948
`option`
909949
~~~~~~~~
910950
Processes the specified option so that git fast-import behaves in a
@@ -930,6 +970,7 @@ not be passed as option:
930970
* date-format
931971
* import-marks
932972
* export-marks
973+
* cat-blob-fd
933974
* force
934975

935976
Crash Reports

fast-import.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ Format of STDIN stream:
5555
('from' sp committish lf)?
5656
lf?;
5757
58+
cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
59+
5860
checkpoint ::= 'checkpoint' lf
5961
lf?;
6062
@@ -361,6 +363,9 @@ static uintmax_t next_mark;
361363
static struct strbuf new_data = STRBUF_INIT;
362364
static int seen_data_command;
363365

366+
/* Where to write output of cat-blob commands */
367+
static int cat_blob_fd = STDOUT_FILENO;
368+
364369
static void parse_argv(void);
365370

366371
static void write_branch_report(FILE *rpt, struct branch *b)
@@ -2689,6 +2694,81 @@ static void parse_reset_branch(void)
26892694
unread_command_buf = 1;
26902695
}
26912696

2697+
static void cat_blob_write(const char *buf, unsigned long size)
2698+
{
2699+
if (write_in_full(cat_blob_fd, buf, size) != size)
2700+
die_errno("Write to frontend failed");
2701+
}
2702+
2703+
static void cat_blob(struct object_entry *oe, unsigned char sha1[20])
2704+
{
2705+
struct strbuf line = STRBUF_INIT;
2706+
unsigned long size;
2707+
enum object_type type = 0;
2708+
char *buf;
2709+
2710+
if (!oe || oe->pack_id == MAX_PACK_ID) {
2711+
buf = read_sha1_file(sha1, &type, &size);
2712+
} else {
2713+
type = oe->type;
2714+
buf = gfi_unpack_entry(oe, &size);
2715+
}
2716+
2717+
/*
2718+
* Output based on batch_one_object() from cat-file.c.
2719+
*/
2720+
if (type <= 0) {
2721+
strbuf_reset(&line);
2722+
strbuf_addf(&line, "%s missing\n", sha1_to_hex(sha1));
2723+
cat_blob_write(line.buf, line.len);
2724+
strbuf_release(&line);
2725+
free(buf);
2726+
return;
2727+
}
2728+
if (!buf)
2729+
die("Can't read object %s", sha1_to_hex(sha1));
2730+
if (type != OBJ_BLOB)
2731+
die("Object %s is a %s but a blob was expected.",
2732+
sha1_to_hex(sha1), typename(type));
2733+
strbuf_reset(&line);
2734+
strbuf_addf(&line, "%s %s %lu\n", sha1_to_hex(sha1),
2735+
typename(type), size);
2736+
cat_blob_write(line.buf, line.len);
2737+
strbuf_release(&line);
2738+
cat_blob_write(buf, size);
2739+
cat_blob_write("\n", 1);
2740+
free(buf);
2741+
}
2742+
2743+
static void parse_cat_blob(void)
2744+
{
2745+
const char *p;
2746+
struct object_entry *oe = oe;
2747+
unsigned char sha1[20];
2748+
2749+
/* cat-blob SP <object> LF */
2750+
p = command_buf.buf + strlen("cat-blob ");
2751+
if (*p == ':') {
2752+
char *x;
2753+
oe = find_mark(strtoumax(p + 1, &x, 10));
2754+
if (x == p + 1)
2755+
die("Invalid mark: %s", command_buf.buf);
2756+
if (!oe)
2757+
die("Unknown mark: %s", command_buf.buf);
2758+
if (*x)
2759+
die("Garbage after mark: %s", command_buf.buf);
2760+
hashcpy(sha1, oe->idx.sha1);
2761+
} else {
2762+
if (get_sha1_hex(p, sha1))
2763+
die("Invalid SHA1: %s", command_buf.buf);
2764+
if (p[40])
2765+
die("Garbage after SHA1: %s", command_buf.buf);
2766+
oe = find_object(sha1);
2767+
}
2768+
2769+
cat_blob(oe, sha1);
2770+
}
2771+
26922772
static void parse_checkpoint(void)
26932773
{
26942774
if (object_count) {
@@ -2773,6 +2853,14 @@ static void option_export_marks(const char *marks)
27732853
safe_create_leading_directories_const(export_marks_file);
27742854
}
27752855

2856+
static void option_cat_blob_fd(const char *fd)
2857+
{
2858+
unsigned long n = ulong_arg("--cat-blob-fd", fd);
2859+
if (n > (unsigned long) INT_MAX)
2860+
die("--cat-blob-fd cannot exceed %d", INT_MAX);
2861+
cat_blob_fd = (int) n;
2862+
}
2863+
27762864
static void option_export_pack_edges(const char *edges)
27772865
{
27782866
if (pack_edges)
@@ -2826,6 +2914,8 @@ static int parse_one_feature(const char *feature, int from_stream)
28262914
option_import_marks(feature + 13, from_stream);
28272915
} else if (!prefixcmp(feature, "export-marks=")) {
28282916
option_export_marks(feature + 13);
2917+
} else if (!strcmp(feature, "cat-blob")) {
2918+
; /* Don't die - this feature is supported */
28292919
} else if (!prefixcmp(feature, "relative-marks")) {
28302920
relative_marks_paths = 1;
28312921
} else if (!prefixcmp(feature, "no-relative-marks")) {
@@ -2920,6 +3010,11 @@ static void parse_argv(void)
29203010
if (parse_one_feature(a + 2, 0))
29213011
continue;
29223012

3013+
if (!prefixcmp(a + 2, "cat-blob-fd=")) {
3014+
option_cat_blob_fd(a + 2 + strlen("cat-blob-fd="));
3015+
continue;
3016+
}
3017+
29233018
die("unknown option %s", a);
29243019
}
29253020
if (i != global_argc)
@@ -2971,6 +3066,8 @@ int main(int argc, const char **argv)
29713066
parse_new_tag();
29723067
else if (!prefixcmp(command_buf.buf, "reset "))
29733068
parse_reset_branch();
3069+
else if (!prefixcmp(command_buf.buf, "cat-blob "))
3070+
parse_cat_blob();
29743071
else if (!strcmp("checkpoint", command_buf.buf))
29753072
parse_checkpoint();
29763073
else if (!prefixcmp(command_buf.buf, "progress "))

0 commit comments

Comments
 (0)