Skip to content

Commit be56862

Browse files
SRabbeliergitster
authored andcommitted
fast-import: introduce 'done' command
Add a 'done' command that causes fast-import to stop reading from the stream and exit. If the new --done command line flag was passed on the command line (or a "feature done" declaration included at the start of the stream), make the 'done' command mandatory. So "git fast-import --done"'s input format will be prefix-free, making errors easier to detect when they show up as early termination at some convenient time of the upstream of a pipe writing to fast-import. Another possible application of the 'done' command would to be allow a fast-import stream that is only a small part of a larger encapsulating stream to be easily parsed, leaving the file offset after the "done\n" so the other application can pick up from there. This patch does not teach fast-import to do that --- fast-import still uses buffered input (stdio). Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Sverre Rabbelier <[email protected]> Acked-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 460d102 commit be56862

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

Documentation/git-fast-import.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ OPTIONS
101101
when the `cat-blob` command is encountered in the stream.
102102
The default behaviour is to write to `stdout`.
103103

104+
--done::
105+
Require a `done` command at the end of the stream.
106+
This option might be useful for detecting errors that
107+
cause the frontend to terminate before it has started to
108+
write a stream.
109+
104110
--export-pack-edges=<file>::
105111
After creating a packfile, print a line of data to
106112
<file> listing the filename of the packfile and the last
@@ -330,6 +336,11 @@ and control the current import process. More detailed discussion
330336
standard output. This command is optional and is not needed
331337
to perform an import.
332338

339+
`done`::
340+
Marks the end of the stream. This command is optional
341+
unless the `done` feature was requested using the
342+
`--done` command line option or `feature done` command.
343+
333344
`cat-blob`::
334345
Causes fast-import to print a blob in 'cat-file --batch'
335346
format to the file descriptor set with `--cat-blob-fd` or
@@ -1015,6 +1026,11 @@ notes::
10151026
Versions of fast-import not supporting notes will exit
10161027
with a message indicating so.
10171028

1029+
done::
1030+
Error out if the stream ends without a 'done' command.
1031+
Without this feature, errors causing the frontend to end
1032+
abruptly at a convenient point in the stream can go
1033+
undetected.
10181034

10191035
`option`
10201036
~~~~~~~~
@@ -1044,6 +1060,15 @@ not be passed as option:
10441060
* cat-blob-fd
10451061
* force
10461062

1063+
`done`
1064+
~~~~~~
1065+
If the `done` feature is not in use, treated as if EOF was read.
1066+
This can be used to tell fast-import to finish early.
1067+
1068+
If the `--done` command line option or `feature done` command is
1069+
in use, the `done` command is mandatory and marks the end of the
1070+
stream.
1071+
10471072
Crash Reports
10481073
-------------
10491074
If fast-import is supplied invalid input it will terminate with a

fast-import.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ static unsigned int cmd_save = 100;
354354
static uintmax_t next_mark;
355355
static struct strbuf new_data = STRBUF_INIT;
356356
static int seen_data_command;
357+
static int require_explicit_termination;
357358

358359
/* Signal handling */
359360
static volatile sig_atomic_t checkpoint_requested;
@@ -3139,6 +3140,8 @@ static int parse_one_feature(const char *feature, int from_stream)
31393140
relative_marks_paths = 1;
31403141
} else if (!strcmp(feature, "no-relative-marks")) {
31413142
relative_marks_paths = 0;
3143+
} else if (!strcmp(feature, "done")) {
3144+
require_explicit_termination = 1;
31423145
} else if (!strcmp(feature, "force")) {
31433146
force_update = 1;
31443147
} else if (!strcmp(feature, "notes") || !strcmp(feature, "ls")) {
@@ -3288,6 +3291,8 @@ int main(int argc, const char **argv)
32883291
parse_reset_branch();
32893292
else if (!strcmp("checkpoint", command_buf.buf))
32903293
parse_checkpoint();
3294+
else if (!strcmp("done", command_buf.buf))
3295+
break;
32913296
else if (!prefixcmp(command_buf.buf, "progress "))
32923297
parse_progress();
32933298
else if (!prefixcmp(command_buf.buf, "feature "))
@@ -3307,6 +3312,9 @@ int main(int argc, const char **argv)
33073312
if (!seen_data_command)
33083313
parse_argv();
33093314

3315+
if (require_explicit_termination && feof(stdin))
3316+
die("stream ends early");
3317+
33103318
end_packfile();
33113319

33123320
dump_branches();

t/t9300-fast-import.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,48 @@ test_expect_success 'R: quiet option results in no stats being output' '
21972197
test_cmp empty output
21982198
'
21992199

2200+
test_expect_success 'R: feature done means terminating "done" is mandatory' '
2201+
echo feature done | test_must_fail git fast-import &&
2202+
test_must_fail git fast-import --done </dev/null
2203+
'
2204+
2205+
test_expect_success 'R: terminating "done" with trailing gibberish is ok' '
2206+
git fast-import <<-\EOF &&
2207+
feature done
2208+
done
2209+
trailing gibberish
2210+
EOF
2211+
git fast-import <<-\EOF
2212+
done
2213+
more trailing gibberish
2214+
EOF
2215+
'
2216+
2217+
test_expect_success 'R: terminating "done" within commit' '
2218+
cat >expect <<-\EOF &&
2219+
OBJID
2220+
:000000 100644 OBJID OBJID A hello.c
2221+
:000000 100644 OBJID OBJID A hello2.c
2222+
EOF
2223+
git fast-import <<-EOF &&
2224+
commit refs/heads/done-ends
2225+
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
2226+
data <<EOT
2227+
Commit terminated by "done" command
2228+
EOT
2229+
M 100644 inline hello.c
2230+
data <<EOT
2231+
Hello, world.
2232+
EOT
2233+
C hello.c hello2.c
2234+
done
2235+
EOF
2236+
git rev-list done-ends |
2237+
git diff-tree -r --stdin --root --always |
2238+
sed -e "s/$_x40/OBJID/g" >actual &&
2239+
test_cmp expect actual
2240+
'
2241+
22002242
cat >input <<EOF
22012243
option git non-existing-option
22022244
EOF

0 commit comments

Comments
 (0)