2008-04-23 21:17:43 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='git cat-file'
|
|
|
|
|
|
|
|
. ./test-lib.sh
|
|
|
|
|
2021-12-28 14:28:41 +01:00
|
|
|
test_cmdmode_usage () {
|
|
|
|
test_expect_code 129 "$@" 2>err &&
|
|
|
|
grep "^error:.*is incompatible with" err
|
|
|
|
}
|
|
|
|
|
|
|
|
for switches in \
|
|
|
|
'-e -p' \
|
|
|
|
'-p -t' \
|
|
|
|
'-t -s' \
|
|
|
|
'-s --textconv' \
|
2021-12-28 14:28:46 +01:00
|
|
|
'--textconv --filters' \
|
|
|
|
'--batch-all-objects -e'
|
2021-12-28 14:28:41 +01:00
|
|
|
do
|
|
|
|
test_expect_success "usage: cmdmode $switches" '
|
|
|
|
test_cmdmode_usage git cat-file $switches
|
|
|
|
'
|
|
|
|
done
|
|
|
|
|
|
|
|
test_incompatible_usage () {
|
|
|
|
test_expect_code 129 "$@" 2>err &&
|
2021-12-28 14:28:47 +01:00
|
|
|
grep -E "^(fatal|error):.*(requires|incompatible with|needs)" err
|
2021-12-28 14:28:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for opt in --batch --batch-check
|
|
|
|
do
|
|
|
|
test_expect_success "usage: incompatible options: --path with $opt" '
|
|
|
|
test_incompatible_usage git cat-file --path=foo $opt
|
|
|
|
'
|
|
|
|
done
|
|
|
|
|
2021-12-28 14:28:47 +01:00
|
|
|
test_missing_usage () {
|
|
|
|
test_expect_code 129 "$@" 2>err &&
|
|
|
|
grep -E "^fatal:.*required" err
|
|
|
|
}
|
|
|
|
|
2021-12-28 14:28:41 +01:00
|
|
|
short_modes="-e -p -t -s"
|
|
|
|
cw_modes="--textconv --filters"
|
|
|
|
|
|
|
|
for opt in $cw_modes
|
|
|
|
do
|
|
|
|
test_expect_success "usage: $opt requires another option" '
|
2021-12-28 14:28:47 +01:00
|
|
|
test_missing_usage git cat-file $opt
|
2021-12-28 14:28:41 +01:00
|
|
|
'
|
|
|
|
done
|
|
|
|
|
|
|
|
for opt in $short_modes
|
|
|
|
do
|
|
|
|
test_expect_success "usage: $opt requires another option" '
|
2021-12-28 14:28:47 +01:00
|
|
|
test_missing_usage git cat-file $opt
|
2021-12-28 14:28:41 +01:00
|
|
|
'
|
|
|
|
|
|
|
|
for opt2 in --batch \
|
|
|
|
--batch-check \
|
2021-12-28 14:28:47 +01:00
|
|
|
--follow-symlinks \
|
|
|
|
"--path=foo HEAD:some-path.txt"
|
2021-12-28 14:28:41 +01:00
|
|
|
do
|
2021-12-28 14:28:47 +01:00
|
|
|
test_expect_success "usage: incompatible options: $opt and $opt2" '
|
2021-12-28 14:28:41 +01:00
|
|
|
test_incompatible_usage git cat-file $opt $opt2
|
|
|
|
'
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
2021-12-28 14:28:47 +01:00
|
|
|
test_too_many_arguments () {
|
|
|
|
test_expect_code 129 "$@" 2>err &&
|
|
|
|
grep -E "^fatal: too many arguments$" err
|
|
|
|
}
|
|
|
|
|
2021-12-28 14:28:41 +01:00
|
|
|
for opt in $short_modes $cw_modes
|
|
|
|
do
|
|
|
|
args="one two three"
|
|
|
|
test_expect_success "usage: too many arguments: $opt $args" '
|
2021-12-28 14:28:47 +01:00
|
|
|
test_too_many_arguments git cat-file $opt $args
|
2021-12-28 14:28:41 +01:00
|
|
|
'
|
|
|
|
|
|
|
|
for opt2 in --buffer --follow-symlinks
|
|
|
|
do
|
|
|
|
test_expect_success "usage: incompatible arguments: $opt with batch option $opt2" '
|
2021-12-28 14:28:47 +01:00
|
|
|
test_incompatible_usage git cat-file $opt $opt2
|
2021-12-28 14:28:41 +01:00
|
|
|
'
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
for opt in --buffer \
|
|
|
|
--follow-symlinks \
|
builtin/cat-file.c: support NUL-delimited input with `-z`
When callers are using `cat-file` via one of the stdin-driven `--batch`
modes, all input is newline-delimited. This presents a problem when
callers wish to ask about, e.g. tree-entries that have a newline
character present in their filename.
To support this niche scenario, introduce a new `-z` mode to the
`--batch`, `--batch-check`, and `--batch-command` suite of options that
instructs `cat-file` to treat its input as NUL-delimited, allowing the
individual commands themselves to have newlines present.
The refactoring here is slightly unfortunate, since we turn loops like:
while (strbuf_getline(&buf, stdin) != EOF)
into:
while (1) {
int ret;
if (opt->nul_terminated)
ret = strbuf_getline_nul(&input, stdin);
else
ret = strbuf_getline(&input, stdin);
if (ret == EOF)
break;
}
It's tempting to think that we could use `strbuf_getwholeline()` and
specify either `\n` or `\0` as the terminating character. But for input
on platforms that include a CR character preceeding the LF, this
wouldn't quite be the same, since `strbuf_getline(...)` will trim any
trailing CR, while `strbuf_getwholeline(&buf, stdin, '\n')` will not.
In the future, we could clean this up further by introducing a variant
of `strbuf_getwholeline()` that addresses the aforementioned gap, but
that approach felt too heavy-handed for this pair of uses.
Some tests are added in t1006 to ensure that `cat-file` produces the
same output in `--batch`, `--batch-check`, and `--batch-command` modes
with and without the new `-z` option.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:29:05 +02:00
|
|
|
--batch-all-objects \
|
|
|
|
-z
|
2021-12-28 14:28:41 +01:00
|
|
|
do
|
2021-12-28 14:28:47 +01:00
|
|
|
test_expect_success "usage: bad option combination: $opt without batch mode" '
|
|
|
|
test_incompatible_usage git cat-file $opt &&
|
|
|
|
test_incompatible_usage git cat-file $opt commit HEAD
|
2021-12-28 14:28:41 +01:00
|
|
|
'
|
|
|
|
done
|
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
echo_without_newline () {
|
|
|
|
printf '%s' "$*"
|
|
|
|
}
|
|
|
|
|
builtin/cat-file.c: support NUL-delimited input with `-z`
When callers are using `cat-file` via one of the stdin-driven `--batch`
modes, all input is newline-delimited. This presents a problem when
callers wish to ask about, e.g. tree-entries that have a newline
character present in their filename.
To support this niche scenario, introduce a new `-z` mode to the
`--batch`, `--batch-check`, and `--batch-command` suite of options that
instructs `cat-file` to treat its input as NUL-delimited, allowing the
individual commands themselves to have newlines present.
The refactoring here is slightly unfortunate, since we turn loops like:
while (strbuf_getline(&buf, stdin) != EOF)
into:
while (1) {
int ret;
if (opt->nul_terminated)
ret = strbuf_getline_nul(&input, stdin);
else
ret = strbuf_getline(&input, stdin);
if (ret == EOF)
break;
}
It's tempting to think that we could use `strbuf_getwholeline()` and
specify either `\n` or `\0` as the terminating character. But for input
on platforms that include a CR character preceeding the LF, this
wouldn't quite be the same, since `strbuf_getline(...)` will trim any
trailing CR, while `strbuf_getwholeline(&buf, stdin, '\n')` will not.
In the future, we could clean this up further by introducing a variant
of `strbuf_getwholeline()` that addresses the aforementioned gap, but
that approach felt too heavy-handed for this pair of uses.
Some tests are added in t1006 to ensure that `cat-file` produces the
same output in `--batch`, `--batch-check`, and `--batch-command` modes
with and without the new `-z` option.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:29:05 +02:00
|
|
|
echo_without_newline_nul () {
|
|
|
|
echo_without_newline "$@" | tr '\n' '\0'
|
|
|
|
}
|
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
strlen () {
|
|
|
|
echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
|
|
|
|
}
|
|
|
|
|
|
|
|
maybe_remove_timestamp () {
|
2022-02-18 19:23:13 +01:00
|
|
|
if test -z "$2"; then
|
|
|
|
echo_without_newline "$1"
|
|
|
|
else
|
|
|
|
echo_without_newline "$(printf '%s\n' "$1" | remove_timestamp)"
|
|
|
|
fi
|
2008-04-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
2022-02-18 19:23:13 +01:00
|
|
|
remove_timestamp () {
|
|
|
|
sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//'
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
run_tests () {
|
|
|
|
type=$1
|
|
|
|
sha1=$2
|
|
|
|
size=$3
|
|
|
|
content=$4
|
|
|
|
pretty_content=$5
|
|
|
|
no_ts=$6
|
|
|
|
|
2008-04-23 21:17:47 +02:00
|
|
|
batch_output="$sha1 $type $size
|
|
|
|
$content"
|
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
test_expect_success "$type exists" '
|
|
|
|
git cat-file -e $sha1
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Type of $type is correct" '
|
2013-07-10 13:36:43 +02:00
|
|
|
echo $type >expect &&
|
|
|
|
git cat-file -t $sha1 >actual &&
|
|
|
|
test_cmp expect actual
|
2008-04-23 21:17:43 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Size of $type is correct" '
|
2013-07-10 13:36:43 +02:00
|
|
|
echo $size >expect &&
|
|
|
|
git cat-file -s $sha1 >actual &&
|
|
|
|
test_cmp expect actual
|
2008-04-23 21:17:43 +02:00
|
|
|
'
|
|
|
|
|
2015-05-03 16:30:02 +02:00
|
|
|
test_expect_success "Type of $type is correct using --allow-unknown-type" '
|
|
|
|
echo $type >expect &&
|
|
|
|
git cat-file -t --allow-unknown-type $sha1 >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Size of $type is correct using --allow-unknown-type" '
|
|
|
|
echo $size >expect &&
|
|
|
|
git cat-file -s --allow-unknown-type $sha1 >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
test -z "$content" ||
|
|
|
|
test_expect_success "Content of $type is correct" '
|
2013-07-10 13:36:43 +02:00
|
|
|
maybe_remove_timestamp "$content" $no_ts >expect &&
|
|
|
|
maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual &&
|
|
|
|
test_cmp expect actual
|
2008-04-23 21:17:43 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Pretty content of $type is correct" '
|
2013-07-10 13:36:43 +02:00
|
|
|
maybe_remove_timestamp "$pretty_content" $no_ts >expect &&
|
|
|
|
maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual &&
|
|
|
|
test_cmp expect actual
|
2008-04-23 21:17:43 +02:00
|
|
|
'
|
2008-04-23 21:17:46 +02:00
|
|
|
|
2008-04-23 21:17:47 +02:00
|
|
|
test -z "$content" ||
|
|
|
|
test_expect_success "--batch output of $type is correct" '
|
2013-07-10 13:36:43 +02:00
|
|
|
maybe_remove_timestamp "$batch_output" $no_ts >expect &&
|
|
|
|
maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual &&
|
|
|
|
test_cmp expect actual
|
2008-04-23 21:17:47 +02:00
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:46 +02:00
|
|
|
test_expect_success "--batch-check output of $type is correct" '
|
2013-07-10 13:36:43 +02:00
|
|
|
echo "$sha1 $type $size" >expect &&
|
|
|
|
echo_without_newline $sha1 | git cat-file --batch-check >actual &&
|
|
|
|
test_cmp expect actual
|
2008-04-23 21:17:46 +02:00
|
|
|
'
|
2013-07-10 13:45:47 +02:00
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
for opt in --buffer --no-buffer
|
|
|
|
do
|
|
|
|
test -z "$content" ||
|
|
|
|
test_expect_success "--batch-command $opt output of $type content is correct" '
|
|
|
|
maybe_remove_timestamp "$batch_output" $no_ts >expect &&
|
|
|
|
maybe_remove_timestamp "$(test_write_lines "contents $sha1" |
|
|
|
|
git cat-file --batch-command $opt)" $no_ts >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "--batch-command $opt output of $type info is correct" '
|
|
|
|
echo "$sha1 $type $size" >expect &&
|
|
|
|
test_write_lines "info $sha1" |
|
|
|
|
git cat-file --batch-command $opt >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
done
|
|
|
|
|
2013-07-10 13:45:47 +02:00
|
|
|
test_expect_success "custom --batch-check format" '
|
|
|
|
echo "$type $sha1" >expect &&
|
|
|
|
echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
cat-file: only split on whitespace when %(rest) is used
Commit c334b87b (cat-file: split --batch input lines on whitespace,
2013-07-11) taught `cat-file --batch-check` to split input lines on
the first whitespace, and stash everything after the first token
into the %(rest) output format element. It claimed:
Object names cannot contain spaces, so any input with
spaces would have resulted in a "missing" line.
But that is not correct. Refs, object sha1s, and various peeling
suffixes cannot contain spaces, but some object names can. In
particular:
1. Tree paths like "[<tree>]:path with whitespace"
2. Reflog specifications like "@{2 days ago}"
3. Commit searches like "rev^{/grep me}" or ":/grep me"
To remain backwards compatible, we cannot split on whitespace by
default, hence we will ship 1.8.4 with the commit reverted.
Resurrect its attempt but in a weaker form; only do the splitting
when "%(rest)" is used in the output format. Since that element did
not exist at all before c334b87, old scripts cannot be affected.
The existence of object names with spaces does mean that you
cannot reliably do:
echo ":path with space and other data" |
git cat-file --batch-check="%(objectname) %(rest)"
as it would split the path and feed only ":path" to get_sha1. But
that command is nonsensical. If you wanted to see "and other data"
in "%(rest)", git cannot possibly know where the filename ends and
the "rest" begins.
It might be more robust to have something like "-z" to separate the
input elements. But this patch is still a reasonable step before
having that. It makes the easy cases easy; people who do not care
about %(rest) do not have to consider it, and the %(rest) code
handles the spaces and newlines of "rev-list --objects" correctly.
Hard cases remain hard but possible (if you might get whitespace in
your input, you do not get to use %(rest) and must split and join
the output yourself using more flexible tools). And most
importantly, it does not preclude us from having different splitting
rules later if a "-z" (or similar) option is added. So we can make
the hard cases easier later, if we choose to.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-02 13:59:07 +02:00
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
test_expect_success "custom --batch-command format" '
|
|
|
|
echo "$type $sha1" >expect &&
|
|
|
|
echo "info $sha1" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
cat-file: only split on whitespace when %(rest) is used
Commit c334b87b (cat-file: split --batch input lines on whitespace,
2013-07-11) taught `cat-file --batch-check` to split input lines on
the first whitespace, and stash everything after the first token
into the %(rest) output format element. It claimed:
Object names cannot contain spaces, so any input with
spaces would have resulted in a "missing" line.
But that is not correct. Refs, object sha1s, and various peeling
suffixes cannot contain spaces, but some object names can. In
particular:
1. Tree paths like "[<tree>]:path with whitespace"
2. Reflog specifications like "@{2 days ago}"
3. Commit searches like "rev^{/grep me}" or ":/grep me"
To remain backwards compatible, we cannot split on whitespace by
default, hence we will ship 1.8.4 with the commit reverted.
Resurrect its attempt but in a weaker form; only do the splitting
when "%(rest)" is used in the output format. Since that element did
not exist at all before c334b87, old scripts cannot be affected.
The existence of object names with spaces does mean that you
cannot reliably do:
echo ":path with space and other data" |
git cat-file --batch-check="%(objectname) %(rest)"
as it would split the path and feed only ":path" to get_sha1. But
that command is nonsensical. If you wanted to see "and other data"
in "%(rest)", git cannot possibly know where the filename ends and
the "rest" begins.
It might be more robust to have something like "-z" to separate the
input elements. But this patch is still a reasonable step before
having that. It makes the easy cases easy; people who do not care
about %(rest) do not have to consider it, and the %(rest) code
handles the spaces and newlines of "rev-list --objects" correctly.
Hard cases remain hard but possible (if you might get whitespace in
your input, you do not get to use %(rest) and must split and join
the output yourself using more flexible tools). And most
importantly, it does not preclude us from having different splitting
rules later if a "-z" (or similar) option is added. So we can make
the hard cases easier later, if we choose to.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-02 13:59:07 +02:00
|
|
|
test_expect_success '--batch-check with %(rest)' '
|
|
|
|
echo "$type this is some extra content" >expect &&
|
|
|
|
echo "$sha1 this is some extra content" |
|
|
|
|
git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
cat-file: handle --batch format with missing type/size
Commit 98e2092 taught cat-file to stream blobs with --batch,
which requires that we look up the object type before
loading it into memory. As a result, we now print the
object header from information in sha1_object_info, and the
actual contents from the read_sha1_file. We double-check
that the information we printed in the header matches the
content we are about to show.
Later, commit 93d2a60 allowed custom header lines for
--batch, and commit 5b08640 made type lookups optional. As a
result, specifying a header line without the type or size
means that we will not look up those items at all.
This causes our double-checking to erroneously die with an
error; we think the type or size has changed, when in fact
it was simply left at "0".
For the size, we can fix this by only doing the consistency
double-check when we have retrieved the size via
sha1_object_info. In the case that we have not retrieved the
value, that means we also did not print it, so there is
nothing for us to check that we are consistent with.
We could do the same for the type. However, besides our
consistency check, we also care about the type in deciding
whether to stream or not. So instead of handling the case
where we do not know the type, this patch instead makes sure
that we always trigger a type lookup when we are printing,
so that even a format without the type will stream as we
would in the normal case.
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-12 00:15:50 +01:00
|
|
|
|
|
|
|
test -z "$content" ||
|
|
|
|
test_expect_success "--batch without type ($type)" '
|
|
|
|
{
|
|
|
|
echo "$size" &&
|
|
|
|
maybe_remove_timestamp "$content" $no_ts
|
|
|
|
} >expect &&
|
|
|
|
echo $sha1 | git cat-file --batch="%(objectsize)" >actual.full &&
|
|
|
|
maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test -z "$content" ||
|
|
|
|
test_expect_success "--batch without size ($type)" '
|
|
|
|
{
|
|
|
|
echo "$type" &&
|
|
|
|
maybe_remove_timestamp "$content" $no_ts
|
|
|
|
} >expect &&
|
|
|
|
echo $sha1 | git cat-file --batch="%(objecttype)" >actual.full &&
|
|
|
|
maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
2008-04-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
hello_content="Hello World"
|
|
|
|
hello_size=$(strlen "$hello_content")
|
|
|
|
hello_sha1=$(echo_without_newline "$hello_content" | git hash-object --stdin)
|
|
|
|
|
|
|
|
test_expect_success "setup" '
|
|
|
|
echo_without_newline "$hello_content" > hello &&
|
|
|
|
git update-index --add hello
|
|
|
|
'
|
|
|
|
|
|
|
|
run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
|
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
test_expect_success '--batch-command --buffer with flush for blob info' '
|
|
|
|
echo "$hello_sha1 blob $hello_size" >expect &&
|
|
|
|
test_write_lines "info $hello_sha1" "flush" |
|
|
|
|
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
|
|
|
|
git cat-file --batch-command --buffer >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success '--batch-command --buffer without flush for blob info' '
|
|
|
|
touch output &&
|
|
|
|
test_write_lines "info $hello_sha1" |
|
|
|
|
GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
|
|
|
|
git cat-file --batch-command --buffer >>output &&
|
|
|
|
test_must_be_empty output
|
|
|
|
'
|
|
|
|
|
cat-file: only split on whitespace when %(rest) is used
Commit c334b87b (cat-file: split --batch input lines on whitespace,
2013-07-11) taught `cat-file --batch-check` to split input lines on
the first whitespace, and stash everything after the first token
into the %(rest) output format element. It claimed:
Object names cannot contain spaces, so any input with
spaces would have resulted in a "missing" line.
But that is not correct. Refs, object sha1s, and various peeling
suffixes cannot contain spaces, but some object names can. In
particular:
1. Tree paths like "[<tree>]:path with whitespace"
2. Reflog specifications like "@{2 days ago}"
3. Commit searches like "rev^{/grep me}" or ":/grep me"
To remain backwards compatible, we cannot split on whitespace by
default, hence we will ship 1.8.4 with the commit reverted.
Resurrect its attempt but in a weaker form; only do the splitting
when "%(rest)" is used in the output format. Since that element did
not exist at all before c334b87, old scripts cannot be affected.
The existence of object names with spaces does mean that you
cannot reliably do:
echo ":path with space and other data" |
git cat-file --batch-check="%(objectname) %(rest)"
as it would split the path and feed only ":path" to get_sha1. But
that command is nonsensical. If you wanted to see "and other data"
in "%(rest)", git cannot possibly know where the filename ends and
the "rest" begins.
It might be more robust to have something like "-z" to separate the
input elements. But this patch is still a reasonable step before
having that. It makes the easy cases easy; people who do not care
about %(rest) do not have to consider it, and the %(rest) code
handles the spaces and newlines of "rev-list --objects" correctly.
Hard cases remain hard but possible (if you might get whitespace in
your input, you do not get to use %(rest) and must split and join
the output yourself using more flexible tools). And most
importantly, it does not preclude us from having different splitting
rules later if a "-z" (or similar) option is added. So we can make
the hard cases easier later, if we choose to.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-02 13:59:07 +02:00
|
|
|
test_expect_success '--batch-check without %(rest) considers whole line' '
|
|
|
|
echo "$hello_sha1 blob $hello_size" >expect &&
|
|
|
|
git update-index --add --cacheinfo 100644 $hello_sha1 "white space" &&
|
|
|
|
test_when_finished "git update-index --remove \"white space\"" &&
|
|
|
|
echo ":white space" | git cat-file --batch-check >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
tree_sha1=$(git write-tree)
|
2018-09-13 07:17:37 +02:00
|
|
|
tree_size=$(($(test_oid rawsz) + 13))
|
2008-04-23 21:17:43 +02:00
|
|
|
tree_pretty_content="100644 blob $hello_sha1 hello"
|
|
|
|
|
|
|
|
run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
|
|
|
|
|
2013-04-12 00:36:10 +02:00
|
|
|
commit_message="Initial commit"
|
2008-04-23 21:17:43 +02:00
|
|
|
commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
|
2018-09-13 07:17:37 +02:00
|
|
|
commit_size=$(($(test_oid hexsz) + 137))
|
2008-04-23 21:17:43 +02:00
|
|
|
commit_content="tree $tree_sha1
|
2023-01-18 21:35:52 +01:00
|
|
|
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0 +0000
|
|
|
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0 +0000
|
2008-04-23 21:17:43 +02:00
|
|
|
|
|
|
|
$commit_message"
|
|
|
|
|
|
|
|
run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" 1
|
|
|
|
|
|
|
|
tag_header_without_timestamp="object $hello_sha1
|
|
|
|
type blob
|
|
|
|
tag hellotag
|
|
|
|
tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
|
|
|
|
tag_description="This is a tag"
|
2023-01-18 21:35:52 +01:00
|
|
|
tag_content="$tag_header_without_timestamp 0 +0000
|
2008-04-23 21:17:43 +02:00
|
|
|
|
|
|
|
$tag_description"
|
|
|
|
|
mktag: use fsck instead of custom verify_tag()
Change the validation logic in "mktag" to use fsck's fsck_tag()
instead of its own custom parser. Curiously the logic for both dates
back to the same commit[1]. Let's unify them so we're not maintaining
two sets functions to verify that a tag is OK.
The behavior of fsck_tag() and the old "mktag" code being removed here
is different in few aspects.
I think it makes sense to remove some of those checks, namely:
A. fsck only cares that the timezone matches [-+][0-9]{4}. The mktag
code disallowed values larger than 1400.
Yes there's currently no timezone with a greater offset[2], but
since we allow any number of non-offical timezones (e.g. +1234)
passing this through seems fine. Git also won't break in the
future if e.g. French Polynesia decides it needs to outdo the Line
Islands when it comes to timezone extravagance.
B. fsck allows missing author names such as "tagger <email>", mktag
wouldn't, but would allow e.g. "tagger [2 spaces] <email>" (but
not "tagger [1 space] <email>"). Now we allow all of these.
C. Like B, but "mktag" disallowed spaces in the <email> part, fsck
allows it.
In some ways fsck_tag() is stricter than "mktag" was, namely:
D. fsck disallows zero-padded dates, but mktag didn't care. So
e.g. the timestamp "0000000000 +0000" produces an error now. A
test in "t1006-cat-file.sh" relied on this, it's been changed to
use "hash-object" (without fsck) instead.
There was one check I deemed worth keeping by porting it over to
fsck_tag():
E. "mktag" did not allow any custom headers, and by extension (as an
empty commit is allowed) also forbade an extra stray trailing
newline after the headers it knew about.
Add a new check in the "ignore" category to fsck and use it. This
somewhat abuses the facility added in efaba7cc77f (fsck:
optionally ignore specific fsck issues completely, 2015-06-22).
This is somewhat of hack, but probably the least invasive change
we can make here. The fsck command will shuffle these categories
around, e.g. under --strict the "info" becomes a "warn" and "warn"
becomes "error". Existing users of fsck's (and others,
e.g. index-pack) --strict option rely on this.
So we need to put something into a category that'll be ignored by
all existing users of the API. Pretending that
fsck.extraHeaderEntry=error ("ignore" by default) was set serves
to do this for us.
1. ec4465adb38 (Add "tag" objects that can be used to sign other
objects., 2005-04-25)
2. https://en.wikipedia.org/wiki/List_of_UTC_time_offsets
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-05 20:42:46 +01:00
|
|
|
tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
|
2008-04-23 21:17:43 +02:00
|
|
|
tag_size=$(strlen "$tag_content")
|
|
|
|
|
cat-file: print tags raw for "cat-file -p"
When "cat-file -p" prints commits, it shows them in their
raw format, since git's format is already human-readable.
For tags, however, we print the whole thing raw except for
one thing: we convert the timestamp on the tagger line into a
human-readable date.
This dates all the way back to a0f15fa (Pretty-print tagger
dates, 2006-03-01). At that time there was no other way to
pretty-print a tag. These days, however, neither of those
matters much. The normal way to pretty-print a tag is with
"git show", which is much more flexible than "cat-file -p".
Commit a0f15fa also built "verify-tag --verbose" (and
subsequently "tag -v") around the "cat-file -p" output.
However, that behavior was lost in commit 62e09ce (Make git
tag a builtin, 2007-07-20), and we went back to printing
the raw tag contents. Nobody seems to have noticed the bug
since then (and it is arguably a saner behavior anyway, as
it shows the actual bytes for which we verified the
signature).
Let's drop the tagger-date formatting for "cat-file -p". It
makes us more consistent with cat-file's commit
pretty-printer, and as a bonus, we can drop the hand-rolled
tag parsing code in cat-file (which happened to behave
inconsistently with the tag pretty-printing code elsewhere).
This is a change of output format, so it's possible that
some callers could considered this a regression. However,
the original behavior was arguably a bug (due to the
inconsistency with commits), likely nobody was relying on it
(even we do not use it ourselves these days), and anyone
relying on the "-p" pretty-printer should be able to expect
a change in the output format (i.e., while "cat-file" is
plumbing, the output format of "-p" was never guaranteed to
be stable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-17 23:00:48 +02:00
|
|
|
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1
|
2008-04-23 21:17:43 +02:00
|
|
|
|
|
|
|
test_expect_success \
|
|
|
|
"Reach a blob from a tag pointing to it" \
|
|
|
|
"test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
|
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
for batch in batch batch-check batch-command
|
2008-04-23 21:17:46 +02:00
|
|
|
do
|
2008-04-23 21:17:47 +02:00
|
|
|
for opt in t s e p
|
|
|
|
do
|
|
|
|
test_expect_success "Passing -$opt with --$batch fails" '
|
|
|
|
test_must_fail git cat-file --$batch -$opt $hello_sha1
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Passing --$batch with -$opt fails" '
|
|
|
|
test_must_fail git cat-file -$opt --$batch $hello_sha1
|
|
|
|
'
|
|
|
|
done
|
|
|
|
|
|
|
|
test_expect_success "Passing <type> with --$batch fails" '
|
|
|
|
test_must_fail git cat-file --$batch blob $hello_sha1
|
2008-04-23 21:17:46 +02:00
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:47 +02:00
|
|
|
test_expect_success "Passing --$batch with <type> fails" '
|
|
|
|
test_must_fail git cat-file blob --$batch $hello_sha1
|
2008-04-23 21:17:46 +02:00
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:47 +02:00
|
|
|
test_expect_success "Passing sha1 with --$batch fails" '
|
|
|
|
test_must_fail git cat-file --$batch $hello_sha1
|
|
|
|
'
|
|
|
|
done
|
2008-04-23 21:17:46 +02:00
|
|
|
|
2015-05-20 19:03:40 +02:00
|
|
|
for opt in t s e p
|
|
|
|
do
|
|
|
|
test_expect_success "Passing -$opt with --follow-symlinks fails" '
|
|
|
|
test_must_fail git cat-file --follow-symlinks -$opt $hello_sha1
|
|
|
|
'
|
|
|
|
done
|
|
|
|
|
2008-06-09 02:02:21 +02:00
|
|
|
test_expect_success "--batch-check for a non-existent named object" '
|
|
|
|
test "foobar42 missing
|
|
|
|
foobar84 missing" = \
|
tests: fix broken &&-chains in `$(...)` command substitutions
The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.
Fix broken &&-chains in `$(...)` command substitutions in order to
reduce the number of possible lurking bugs.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-09 06:11:07 +01:00
|
|
|
"$( ( echo foobar42 && echo_without_newline foobar84 ) | git cat-file --batch-check)"
|
2008-06-09 02:02:21 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "--batch-check for a non-existent hash" '
|
|
|
|
test "0000000000000000000000000000000000000042 missing
|
|
|
|
0000000000000000000000000000000000000084 missing" = \
|
tests: fix broken &&-chains in `$(...)` command substitutions
The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.
Fix broken &&-chains in `$(...)` command substitutions in order to
reduce the number of possible lurking bugs.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-09 06:11:07 +01:00
|
|
|
"$( ( echo 0000000000000000000000000000000000000042 &&
|
|
|
|
echo_without_newline 0000000000000000000000000000000000000084 ) |
|
2018-10-05 23:54:03 +02:00
|
|
|
git cat-file --batch-check)"
|
2008-06-09 02:02:21 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "--batch for an existent and a non-existent hash" '
|
|
|
|
test "$tag_sha1 tag $tag_size
|
|
|
|
$tag_content
|
|
|
|
0000000000000000000000000000000000000000 missing" = \
|
tests: fix broken &&-chains in `$(...)` command substitutions
The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.
Fix broken &&-chains in `$(...)` command substitutions in order to
reduce the number of possible lurking bugs.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-09 06:11:07 +01:00
|
|
|
"$( ( echo $tag_sha1 &&
|
|
|
|
echo_without_newline 0000000000000000000000000000000000000000 ) |
|
2018-10-05 23:54:03 +02:00
|
|
|
git cat-file --batch)"
|
2008-04-23 21:17:46 +02:00
|
|
|
'
|
|
|
|
|
2016-08-09 10:53:38 +02:00
|
|
|
test_expect_success "--batch-check for an empty line" '
|
2008-04-23 21:17:46 +02:00
|
|
|
test " missing" = "$(echo | git cat-file --batch-check)"
|
|
|
|
'
|
|
|
|
|
2013-11-06 19:00:57 +01:00
|
|
|
test_expect_success 'empty --batch-check notices missing object' '
|
2018-05-13 04:24:13 +02:00
|
|
|
echo "$ZERO_OID missing" >expect &&
|
|
|
|
echo "$ZERO_OID" | git cat-file --batch-check="" >actual &&
|
2013-11-06 19:00:57 +01:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:47 +02:00
|
|
|
batch_input="$hello_sha1
|
|
|
|
$commit_sha1
|
|
|
|
$tag_sha1
|
|
|
|
deadbeef
|
|
|
|
|
|
|
|
"
|
|
|
|
|
|
|
|
batch_output="$hello_sha1 blob $hello_size
|
|
|
|
$hello_content
|
|
|
|
$commit_sha1 commit $commit_size
|
|
|
|
$commit_content
|
|
|
|
$tag_sha1 tag $tag_size
|
|
|
|
$tag_content
|
|
|
|
deadbeef missing
|
|
|
|
missing"
|
|
|
|
|
2008-05-23 16:19:43 +02:00
|
|
|
test_expect_success '--batch with multiple sha1s gives correct format' '
|
|
|
|
test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)"
|
|
|
|
'
|
2008-04-23 21:17:47 +02:00
|
|
|
|
builtin/cat-file.c: support NUL-delimited input with `-z`
When callers are using `cat-file` via one of the stdin-driven `--batch`
modes, all input is newline-delimited. This presents a problem when
callers wish to ask about, e.g. tree-entries that have a newline
character present in their filename.
To support this niche scenario, introduce a new `-z` mode to the
`--batch`, `--batch-check`, and `--batch-command` suite of options that
instructs `cat-file` to treat its input as NUL-delimited, allowing the
individual commands themselves to have newlines present.
The refactoring here is slightly unfortunate, since we turn loops like:
while (strbuf_getline(&buf, stdin) != EOF)
into:
while (1) {
int ret;
if (opt->nul_terminated)
ret = strbuf_getline_nul(&input, stdin);
else
ret = strbuf_getline(&input, stdin);
if (ret == EOF)
break;
}
It's tempting to think that we could use `strbuf_getwholeline()` and
specify either `\n` or `\0` as the terminating character. But for input
on platforms that include a CR character preceeding the LF, this
wouldn't quite be the same, since `strbuf_getline(...)` will trim any
trailing CR, while `strbuf_getwholeline(&buf, stdin, '\n')` will not.
In the future, we could clean this up further by introducing a variant
of `strbuf_getwholeline()` that addresses the aforementioned gap, but
that approach felt too heavy-handed for this pair of uses.
Some tests are added in t1006 to ensure that `cat-file` produces the
same output in `--batch`, `--batch-check`, and `--batch-command` modes
with and without the new `-z` option.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:29:05 +02:00
|
|
|
test_expect_success '--batch, -z with multiple sha1s gives correct format' '
|
|
|
|
echo_without_newline_nul "$batch_input" >in &&
|
|
|
|
test "$(maybe_remove_timestamp "$batch_output" 1)" = \
|
|
|
|
"$(maybe_remove_timestamp "$(git cat-file --batch -z <in)" 1)"
|
|
|
|
'
|
|
|
|
|
2008-04-23 21:17:46 +02:00
|
|
|
batch_check_input="$hello_sha1
|
|
|
|
$tree_sha1
|
|
|
|
$commit_sha1
|
|
|
|
$tag_sha1
|
|
|
|
deadbeef
|
|
|
|
|
|
|
|
"
|
|
|
|
|
|
|
|
batch_check_output="$hello_sha1 blob $hello_size
|
|
|
|
$tree_sha1 tree $tree_size
|
|
|
|
$commit_sha1 commit $commit_size
|
|
|
|
$tag_sha1 tag $tag_size
|
|
|
|
deadbeef missing
|
|
|
|
missing"
|
|
|
|
|
|
|
|
test_expect_success "--batch-check with multiple sha1s gives correct format" '
|
|
|
|
test "$batch_check_output" = \
|
|
|
|
"$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
|
|
|
|
'
|
|
|
|
|
builtin/cat-file.c: support NUL-delimited input with `-z`
When callers are using `cat-file` via one of the stdin-driven `--batch`
modes, all input is newline-delimited. This presents a problem when
callers wish to ask about, e.g. tree-entries that have a newline
character present in their filename.
To support this niche scenario, introduce a new `-z` mode to the
`--batch`, `--batch-check`, and `--batch-command` suite of options that
instructs `cat-file` to treat its input as NUL-delimited, allowing the
individual commands themselves to have newlines present.
The refactoring here is slightly unfortunate, since we turn loops like:
while (strbuf_getline(&buf, stdin) != EOF)
into:
while (1) {
int ret;
if (opt->nul_terminated)
ret = strbuf_getline_nul(&input, stdin);
else
ret = strbuf_getline(&input, stdin);
if (ret == EOF)
break;
}
It's tempting to think that we could use `strbuf_getwholeline()` and
specify either `\n` or `\0` as the terminating character. But for input
on platforms that include a CR character preceeding the LF, this
wouldn't quite be the same, since `strbuf_getline(...)` will trim any
trailing CR, while `strbuf_getwholeline(&buf, stdin, '\n')` will not.
In the future, we could clean this up further by introducing a variant
of `strbuf_getwholeline()` that addresses the aforementioned gap, but
that approach felt too heavy-handed for this pair of uses.
Some tests are added in t1006 to ensure that `cat-file` produces the
same output in `--batch`, `--batch-check`, and `--batch-command` modes
with and without the new `-z` option.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:29:05 +02:00
|
|
|
test_expect_success "--batch-check, -z with multiple sha1s gives correct format" '
|
|
|
|
echo_without_newline_nul "$batch_check_input" >in &&
|
|
|
|
test "$batch_check_output" = "$(git cat-file --batch-check -z <in)"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
|
|
|
|
touch -- "newline${LF}embedded" &&
|
|
|
|
git add -- "newline${LF}embedded" &&
|
|
|
|
git commit -m "file with newline embedded" &&
|
|
|
|
test_tick &&
|
|
|
|
|
|
|
|
printf "HEAD:newline${LF}embedded" >in &&
|
|
|
|
git cat-file --batch-check -z <in >actual &&
|
|
|
|
|
|
|
|
echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2022-07-23 01:29:02 +02:00
|
|
|
batch_command_multiple_info="info $hello_sha1
|
|
|
|
info $tree_sha1
|
|
|
|
info $commit_sha1
|
|
|
|
info $tag_sha1
|
|
|
|
info deadbeef"
|
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
test_expect_success '--batch-command with multiple info calls gives correct format' '
|
|
|
|
cat >expect <<-EOF &&
|
|
|
|
$hello_sha1 blob $hello_size
|
|
|
|
$tree_sha1 tree $tree_size
|
|
|
|
$commit_sha1 commit $commit_size
|
|
|
|
$tag_sha1 tag $tag_size
|
|
|
|
deadbeef missing
|
|
|
|
EOF
|
|
|
|
|
2022-07-23 01:29:02 +02:00
|
|
|
echo "$batch_command_multiple_info" >in &&
|
|
|
|
git cat-file --batch-command --buffer <in >actual &&
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
|
builtin/cat-file.c: support NUL-delimited input with `-z`
When callers are using `cat-file` via one of the stdin-driven `--batch`
modes, all input is newline-delimited. This presents a problem when
callers wish to ask about, e.g. tree-entries that have a newline
character present in their filename.
To support this niche scenario, introduce a new `-z` mode to the
`--batch`, `--batch-check`, and `--batch-command` suite of options that
instructs `cat-file` to treat its input as NUL-delimited, allowing the
individual commands themselves to have newlines present.
The refactoring here is slightly unfortunate, since we turn loops like:
while (strbuf_getline(&buf, stdin) != EOF)
into:
while (1) {
int ret;
if (opt->nul_terminated)
ret = strbuf_getline_nul(&input, stdin);
else
ret = strbuf_getline(&input, stdin);
if (ret == EOF)
break;
}
It's tempting to think that we could use `strbuf_getwholeline()` and
specify either `\n` or `\0` as the terminating character. But for input
on platforms that include a CR character preceeding the LF, this
wouldn't quite be the same, since `strbuf_getline(...)` will trim any
trailing CR, while `strbuf_getwholeline(&buf, stdin, '\n')` will not.
In the future, we could clean this up further by introducing a variant
of `strbuf_getwholeline()` that addresses the aforementioned gap, but
that approach felt too heavy-handed for this pair of uses.
Some tests are added in t1006 to ensure that `cat-file` produces the
same output in `--batch`, `--batch-check`, and `--batch-command` modes
with and without the new `-z` option.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:29:05 +02:00
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
|
|
|
git cat-file --batch-command --buffer -z <in >actual &&
|
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2022-07-23 01:29:02 +02:00
|
|
|
batch_command_multiple_contents="contents $hello_sha1
|
|
|
|
contents $commit_sha1
|
|
|
|
contents $tag_sha1
|
|
|
|
contents deadbeef
|
|
|
|
flush"
|
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
test_expect_success '--batch-command with multiple command calls gives correct format' '
|
|
|
|
remove_timestamp >expect <<-EOF &&
|
|
|
|
$hello_sha1 blob $hello_size
|
|
|
|
$hello_content
|
|
|
|
$commit_sha1 commit $commit_size
|
|
|
|
$commit_content
|
|
|
|
$tag_sha1 tag $tag_size
|
|
|
|
$tag_content
|
|
|
|
deadbeef missing
|
|
|
|
EOF
|
|
|
|
|
2022-07-23 01:29:02 +02:00
|
|
|
echo "$batch_command_multiple_contents" >in &&
|
|
|
|
git cat-file --batch-command --buffer <in >actual_raw &&
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
|
builtin/cat-file.c: support NUL-delimited input with `-z`
When callers are using `cat-file` via one of the stdin-driven `--batch`
modes, all input is newline-delimited. This presents a problem when
callers wish to ask about, e.g. tree-entries that have a newline
character present in their filename.
To support this niche scenario, introduce a new `-z` mode to the
`--batch`, `--batch-check`, and `--batch-command` suite of options that
instructs `cat-file` to treat its input as NUL-delimited, allowing the
individual commands themselves to have newlines present.
The refactoring here is slightly unfortunate, since we turn loops like:
while (strbuf_getline(&buf, stdin) != EOF)
into:
while (1) {
int ret;
if (opt->nul_terminated)
ret = strbuf_getline_nul(&input, stdin);
else
ret = strbuf_getline(&input, stdin);
if (ret == EOF)
break;
}
It's tempting to think that we could use `strbuf_getwholeline()` and
specify either `\n` or `\0` as the terminating character. But for input
on platforms that include a CR character preceeding the LF, this
wouldn't quite be the same, since `strbuf_getline(...)` will trim any
trailing CR, while `strbuf_getwholeline(&buf, stdin, '\n')` will not.
In the future, we could clean this up further by introducing a variant
of `strbuf_getwholeline()` that addresses the aforementioned gap, but
that approach felt too heavy-handed for this pair of uses.
Some tests are added in t1006 to ensure that `cat-file` produces the
same output in `--batch`, `--batch-check`, and `--batch-command` modes
with and without the new `-z` option.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:29:05 +02:00
|
|
|
remove_timestamp <actual_raw >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
|
|
|
git cat-file --batch-command --buffer -z <in >actual_raw &&
|
|
|
|
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
remove_timestamp <actual_raw >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2013-12-21 15:25:22 +01:00
|
|
|
test_expect_success 'setup blobs which are likely to delta' '
|
2018-03-24 08:44:42 +01:00
|
|
|
test-tool genrandom foo 10240 >foo &&
|
tests: fix broken &&-chains in `{...}` groups
The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.
Fix broken &&-chains in `{...}` groups in order to reduce the number of
possible lurking bugs.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-09 06:11:08 +01:00
|
|
|
{ cat foo && echo plus; } >foo-plus &&
|
2013-12-21 15:25:22 +01:00
|
|
|
git add foo foo-plus &&
|
|
|
|
git commit -m foo &&
|
|
|
|
cat >blobs <<-\EOF
|
|
|
|
HEAD:foo
|
|
|
|
HEAD:foo-plus
|
|
|
|
EOF
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'confirm that neither loose blob is a delta' '
|
2015-03-20 11:07:15 +01:00
|
|
|
cat >expect <<-EOF &&
|
2018-05-13 04:24:13 +02:00
|
|
|
$ZERO_OID
|
|
|
|
$ZERO_OID
|
2013-12-21 15:25:22 +01:00
|
|
|
EOF
|
|
|
|
git cat-file --batch-check="%(deltabase)" <blobs >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
# To avoid relying too much on the current delta heuristics,
|
|
|
|
# we will check only that one of the two objects is a delta
|
|
|
|
# against the other, but not the order. We can do so by just
|
|
|
|
# asking for the base of both, and checking whether either
|
|
|
|
# sha1 appears in the output.
|
|
|
|
test_expect_success '%(deltabase) reports packed delta bases' '
|
|
|
|
git repack -ad &&
|
|
|
|
git cat-file --batch-check="%(deltabase)" <blobs >actual &&
|
|
|
|
{
|
|
|
|
grep "$(git rev-parse HEAD:foo)" actual ||
|
|
|
|
grep "$(git rev-parse HEAD:foo-plus)" actual
|
|
|
|
}
|
|
|
|
'
|
|
|
|
|
2021-10-01 11:16:41 +02:00
|
|
|
test_expect_success 'setup bogus data' '
|
|
|
|
bogus_short_type="bogus" &&
|
|
|
|
bogus_short_content="bogus" &&
|
|
|
|
bogus_short_size=$(strlen "$bogus_short_content") &&
|
|
|
|
bogus_short_sha1=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) &&
|
|
|
|
|
|
|
|
bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" &&
|
|
|
|
bogus_long_content="bogus" &&
|
|
|
|
bogus_long_size=$(strlen "$bogus_long_content") &&
|
|
|
|
bogus_long_sha1=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin)
|
|
|
|
'
|
2015-05-03 16:30:02 +02:00
|
|
|
|
2021-10-01 11:16:42 +02:00
|
|
|
for arg1 in '' --allow-unknown-type
|
|
|
|
do
|
|
|
|
for arg2 in -s -t -p
|
|
|
|
do
|
|
|
|
if test "$arg1" = "--allow-unknown-type" && test "$arg2" = "-p"
|
|
|
|
then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
test_expect_success "cat-file $arg1 $arg2 error on bogus short OID" '
|
|
|
|
cat >expect <<-\EOF &&
|
|
|
|
fatal: invalid object type
|
|
|
|
EOF
|
|
|
|
|
|
|
|
if test "$arg1" = "--allow-unknown-type"
|
|
|
|
then
|
|
|
|
git cat-file $arg1 $arg2 $bogus_short_sha1
|
|
|
|
else
|
|
|
|
test_must_fail git cat-file $arg1 $arg2 $bogus_short_sha1 >out 2>actual &&
|
|
|
|
test_must_be_empty out &&
|
|
|
|
test_cmp expect actual
|
|
|
|
fi
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "cat-file $arg1 $arg2 error on bogus full OID" '
|
|
|
|
if test "$arg2" = "-p"
|
|
|
|
then
|
|
|
|
cat >expect <<-EOF
|
2021-10-01 11:16:50 +02:00
|
|
|
error: header for $bogus_long_sha1 too long, exceeds 32 bytes
|
2021-10-01 11:16:42 +02:00
|
|
|
fatal: Not a valid object name $bogus_long_sha1
|
|
|
|
EOF
|
|
|
|
else
|
|
|
|
cat >expect <<-EOF
|
2021-10-01 11:16:50 +02:00
|
|
|
error: header for $bogus_long_sha1 too long, exceeds 32 bytes
|
2021-10-01 11:16:42 +02:00
|
|
|
fatal: git cat-file: could not get object info
|
|
|
|
EOF
|
|
|
|
fi &&
|
|
|
|
|
|
|
|
if test "$arg1" = "--allow-unknown-type"
|
|
|
|
then
|
|
|
|
git cat-file $arg1 $arg2 $bogus_short_sha1
|
|
|
|
else
|
|
|
|
test_must_fail git cat-file $arg1 $arg2 $bogus_long_sha1 >out 2>actual &&
|
|
|
|
test_must_be_empty out &&
|
|
|
|
test_cmp expect actual
|
|
|
|
fi
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "cat-file $arg1 $arg2 error on missing short OID" '
|
|
|
|
cat >expect.err <<-EOF &&
|
|
|
|
fatal: Not a valid object name $(test_oid deadbeef_short)
|
|
|
|
EOF
|
|
|
|
test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef_short) >out 2>err.actual &&
|
|
|
|
test_must_be_empty out
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "cat-file $arg1 $arg2 error on missing full OID" '
|
|
|
|
if test "$arg2" = "-p"
|
|
|
|
then
|
|
|
|
cat >expect.err <<-EOF
|
|
|
|
fatal: Not a valid object name $(test_oid deadbeef)
|
|
|
|
EOF
|
|
|
|
else
|
|
|
|
cat >expect.err <<-\EOF
|
|
|
|
fatal: git cat-file: could not get object info
|
|
|
|
EOF
|
|
|
|
fi &&
|
|
|
|
test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef) >out 2>err.actual &&
|
|
|
|
test_must_be_empty out &&
|
|
|
|
test_cmp expect.err err.actual
|
|
|
|
'
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
2021-10-01 11:16:44 +02:00
|
|
|
test_expect_success '-e is OK with a broken object without --allow-unknown-type' '
|
|
|
|
git cat-file -e $bogus_short_sha1
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success '-e can not be combined with --allow-unknown-type' '
|
|
|
|
test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_sha1
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success '-p cannot print a broken object even with --allow-unknown-type' '
|
|
|
|
test_must_fail git cat-file -p $bogus_short_sha1 &&
|
|
|
|
test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_sha1
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success '<type> <hash> does not work with objects of broken types' '
|
|
|
|
cat >err.expect <<-\EOF &&
|
|
|
|
fatal: invalid object type "bogus"
|
|
|
|
EOF
|
|
|
|
test_must_fail git cat-file $bogus_short_type $bogus_short_sha1 2>err.actual &&
|
|
|
|
test_cmp err.expect err.actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'broken types combined with --batch and --batch-check' '
|
|
|
|
echo $bogus_short_sha1 >bogus-oid &&
|
|
|
|
|
|
|
|
cat >err.expect <<-\EOF &&
|
|
|
|
fatal: invalid object type
|
|
|
|
EOF
|
|
|
|
|
|
|
|
test_must_fail git cat-file --batch <bogus-oid 2>err.actual &&
|
|
|
|
test_cmp err.expect err.actual &&
|
|
|
|
|
|
|
|
test_must_fail git cat-file --batch-check <bogus-oid 2>err.actual &&
|
|
|
|
test_cmp err.expect err.actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'the --batch and --batch-check options do not combine with --allow-unknown-type' '
|
|
|
|
test_expect_code 128 git cat-file --batch --allow-unknown-type <bogus-oid &&
|
|
|
|
test_expect_code 128 git cat-file --batch-check --allow-unknown-type <bogus-oid
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'the --allow-unknown-type option does not consider replacement refs' '
|
|
|
|
cat >expect <<-EOF &&
|
|
|
|
$bogus_short_type
|
|
|
|
EOF
|
|
|
|
git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
# Create it manually, as "git replace" will die on bogus
|
|
|
|
# types.
|
|
|
|
head=$(git rev-parse --verify HEAD) &&
|
2021-12-07 14:38:17 +01:00
|
|
|
test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1" &&
|
|
|
|
test-tool ref-store main update-ref msg "refs/replace/$bogus_short_sha1" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&
|
2021-10-01 11:16:44 +02:00
|
|
|
|
|
|
|
cat >expect <<-EOF &&
|
|
|
|
commit
|
|
|
|
EOF
|
|
|
|
git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
2015-05-03 16:30:02 +02:00
|
|
|
|
|
|
|
test_expect_success "Type of broken object is correct" '
|
2021-10-01 11:16:41 +02:00
|
|
|
echo $bogus_short_type >expect &&
|
|
|
|
git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual &&
|
2015-05-03 16:30:02 +02:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Size of broken object is correct" '
|
2021-10-01 11:16:41 +02:00
|
|
|
echo $bogus_short_size >expect &&
|
|
|
|
git cat-file -s --allow-unknown-type $bogus_short_sha1 >actual &&
|
2015-05-03 16:30:02 +02:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
2021-10-05 22:30:36 +02:00
|
|
|
|
|
|
|
test_expect_success 'clean up broken object' '
|
2021-10-26 01:06:56 +02:00
|
|
|
rm .git/objects/$(test_oid_to_path $bogus_short_sha1)
|
2021-10-05 22:30:36 +02:00
|
|
|
'
|
|
|
|
|
2015-05-03 16:30:02 +02:00
|
|
|
test_expect_success "Type of broken object is correct when type is large" '
|
2021-10-01 11:16:41 +02:00
|
|
|
echo $bogus_long_type >expect &&
|
|
|
|
git cat-file -t --allow-unknown-type $bogus_long_sha1 >actual &&
|
2015-05-03 16:30:02 +02:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "Size of large broken object is correct when type is large" '
|
2021-10-01 11:16:41 +02:00
|
|
|
echo $bogus_long_size >expect &&
|
|
|
|
git cat-file -s --allow-unknown-type $bogus_long_sha1 >actual &&
|
2015-05-03 16:30:02 +02:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2021-10-05 22:30:36 +02:00
|
|
|
test_expect_success 'clean up broken object' '
|
2021-10-26 01:06:56 +02:00
|
|
|
rm .git/objects/$(test_oid_to_path $bogus_long_sha1)
|
|
|
|
'
|
|
|
|
|
2021-10-01 11:16:43 +02:00
|
|
|
test_expect_success 'cat-file -t and -s on corrupt loose object' '
|
|
|
|
git init --bare corrupt-loose.git &&
|
|
|
|
(
|
|
|
|
cd corrupt-loose.git &&
|
|
|
|
|
|
|
|
# Setup and create the empty blob and its path
|
|
|
|
empty_path=$(git rev-parse --git-path objects/$(test_oid_to_path "$EMPTY_BLOB")) &&
|
2022-05-13 00:32:18 +02:00
|
|
|
empty_blob=$(git hash-object -w --stdin </dev/null) &&
|
2021-10-01 11:16:43 +02:00
|
|
|
|
|
|
|
# Create another blob and its path
|
|
|
|
echo other >other.blob &&
|
|
|
|
other_blob=$(git hash-object -w --stdin <other.blob) &&
|
|
|
|
other_path=$(git rev-parse --git-path objects/$(test_oid_to_path "$other_blob")) &&
|
|
|
|
|
|
|
|
# Before the swap the size is 0
|
|
|
|
cat >out.expect <<-EOF &&
|
|
|
|
0
|
|
|
|
EOF
|
|
|
|
git cat-file -s "$EMPTY_BLOB" >out.actual 2>err.actual &&
|
|
|
|
test_must_be_empty err.actual &&
|
|
|
|
test_cmp out.expect out.actual &&
|
|
|
|
|
|
|
|
# Swap the two to corrupt the repository
|
|
|
|
mv -f "$other_path" "$empty_path" &&
|
|
|
|
test_must_fail git fsck 2>err.fsck &&
|
fsck: report invalid object type-path combinations
Improve the error that's emitted in cases where we find a loose object
we parse, but which isn't at the location we expect it to be.
Before this change we'd prefix the error with a not-a-OID derived from
the path at which the object was found, due to an emergent behavior in
how we'd end up with an "OID" in these codepaths.
Now we'll instead say what object we hashed, and what path it was
found at. Before this patch series e.g.:
$ git hash-object --stdin -w -t blob </dev/null
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ mv objects/e6/ objects/e7
Would emit ("[...]" used to abbreviate the OIDs):
git fsck
error: hash mismatch for ./objects/e7/9d[...] (expected e79d[...])
error: e79d[...]: object corrupt or missing: ./objects/e7/9d[...]
Now we'll instead emit:
error: e69d[...]: hash-path mismatch, found at: ./objects/e7/9d[...]
Furthermore, we'll do the right thing when the object type and its
location are bad. I.e. this case:
$ git hash-object --stdin -w -t garbage --literally </dev/null
8315a83d2acc4c174aed59430f9a9c4ed926440f
$ mv objects/83 objects/84
As noted in an earlier commits we'd simply die early in those cases,
until preceding commits fixed the hard die on invalid object type:
$ git fsck
fatal: invalid object type
Now we'll instead emit sensible error messages:
$ git fsck
error: 8315[...]: hash-path mismatch, found at: ./objects/84/15[...]
error: 8315[...]: object is of unknown type 'garbage': ./objects/84/15[...]
In both fsck.c and object-file.c we're using null_oid as a sentinel
value for checking whether we got far enough to be certain that the
issue was indeed this OID mismatch.
We need to add the "object corrupt or missing" special-case to deal
with cases where read_loose_object() will return an error before
completing check_object_signature(), e.g. if we have an error in
unpack_loose_rest() because we find garbage after the valid gzip
content:
$ git hash-object --stdin -w -t blob </dev/null
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ chmod 755 objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ echo garbage >>objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ git fsck
error: garbage at end of loose object 'e69d[...]'
error: unable to unpack contents of ./objects/e6/9d[...]
error: e69d[...]: object corrupt or missing: ./objects/e6/9d[...]
There is currently some weird messaging in the edge case when the two
are combined, i.e. because we're not explicitly passing along an error
state about this specific scenario from check_stream_oid() via
read_loose_object() we'll end up printing the null OID if an object is
of an unknown type *and* it can't be unpacked by zlib, e.g.:
$ git hash-object --stdin -w -t garbage --literally </dev/null
8315a83d2acc4c174aed59430f9a9c4ed926440f
$ chmod 755 objects/83/15a83d2acc4c174aed59430f9a9c4ed926440f
$ echo garbage >>objects/83/15a83d2acc4c174aed59430f9a9c4ed926440f
$ /usr/bin/git fsck
fatal: invalid object type
$ ~/g/git/git fsck
error: garbage at end of loose object '8315a83d2acc4c174aed59430f9a9c4ed926440f'
error: unable to unpack contents of ./objects/83/15a83d2acc4c174aed59430f9a9c4ed926440f
error: 8315a83d2acc4c174aed59430f9a9c4ed926440f: object corrupt or missing: ./objects/83/15a83d2acc4c174aed59430f9a9c4ed926440f
error: 0000000000000000000000000000000000000000: object is of unknown type 'garbage': ./objects/83/15a83d2acc4c174aed59430f9a9c4ed926440f
[...]
I think it's OK to leave that for future improvements, which would
involve enum-ifying more error state as we've done with "enum
unpack_loose_header_result" in preceding commits. In these
increasingly more obscure cases the worst that can happen is that
we'll get slightly nonsensical or inapplicable error messages.
There's other such potential edge cases, all of which might produce
some confusing messaging, but still be handled correctly as far as
passing along errors goes. E.g. if check_object_signature() returns
and oideq(real_oid, null_oid()) is true, which could happen if it
returns -1 due to the read_istream() call having failed.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 11:16:53 +02:00
|
|
|
grep "hash-path mismatch" err.fsck &&
|
2021-10-01 11:16:43 +02:00
|
|
|
|
|
|
|
# confirm that cat-file is reading the new swapped-in
|
|
|
|
# blob...
|
|
|
|
cat >out.expect <<-EOF &&
|
|
|
|
blob
|
|
|
|
EOF
|
|
|
|
git cat-file -t "$EMPTY_BLOB" >out.actual 2>err.actual &&
|
|
|
|
test_must_be_empty err.actual &&
|
|
|
|
test_cmp out.expect out.actual &&
|
|
|
|
|
|
|
|
# ... since it has a different size now.
|
|
|
|
cat >out.expect <<-EOF &&
|
|
|
|
6
|
|
|
|
EOF
|
|
|
|
git cat-file -s "$EMPTY_BLOB" >out.actual 2>err.actual &&
|
|
|
|
test_must_be_empty err.actual &&
|
|
|
|
test_cmp out.expect out.actual &&
|
|
|
|
|
|
|
|
# So far "cat-file" has been happy to spew the found
|
|
|
|
# content out as-is. Try to make it zlib-invalid.
|
|
|
|
mv -f other.blob "$empty_path" &&
|
|
|
|
test_must_fail git fsck 2>err.fsck &&
|
2022-05-13 00:32:18 +02:00
|
|
|
cat >expect <<-EOF &&
|
|
|
|
error: inflate: data stream error (incorrect header check)
|
|
|
|
error: unable to unpack header of ./$empty_path
|
|
|
|
error: $empty_blob: object corrupt or missing: ./$empty_path
|
|
|
|
EOF
|
|
|
|
grep "^error: " err.fsck >actual &&
|
|
|
|
test_cmp expect actual
|
2021-10-01 11:16:43 +02:00
|
|
|
)
|
2021-10-05 22:30:36 +02:00
|
|
|
'
|
|
|
|
|
2015-05-20 19:03:40 +02:00
|
|
|
# Tests for git cat-file --follow-symlinks
|
|
|
|
test_expect_success 'prep for symlink tests' '
|
|
|
|
echo_without_newline "$hello_content" >morx &&
|
|
|
|
test_ln_s_add morx same-dir-link &&
|
|
|
|
test_ln_s_add dir link-to-dir &&
|
|
|
|
test_ln_s_add ../fleem out-of-repo-link &&
|
|
|
|
test_ln_s_add .. out-of-repo-link-dir &&
|
|
|
|
test_ln_s_add same-dir-link link-to-link &&
|
|
|
|
test_ln_s_add nope broken-same-dir-link &&
|
|
|
|
mkdir dir &&
|
|
|
|
test_ln_s_add ../morx dir/parent-dir-link &&
|
|
|
|
test_ln_s_add .. dir/link-dir &&
|
|
|
|
test_ln_s_add ../../escape dir/out-of-repo-link &&
|
|
|
|
test_ln_s_add ../.. dir/out-of-repo-link-dir &&
|
|
|
|
test_ln_s_add nope dir/broken-link-in-dir &&
|
|
|
|
mkdir dir/subdir &&
|
|
|
|
test_ln_s_add ../../morx dir/subdir/grandparent-dir-link &&
|
|
|
|
test_ln_s_add ../../../great-escape dir/subdir/out-of-repo-link &&
|
|
|
|
test_ln_s_add ../../.. dir/subdir/out-of-repo-link-dir &&
|
|
|
|
test_ln_s_add ../../../ dir/subdir/out-of-repo-link-dir-trailing &&
|
|
|
|
test_ln_s_add ../parent-dir-link dir/subdir/parent-dir-link-to-link &&
|
|
|
|
echo_without_newline "$hello_content" >dir/subdir/ind2 &&
|
|
|
|
echo_without_newline "$hello_content" >dir/ind1 &&
|
|
|
|
test_ln_s_add dir dirlink &&
|
|
|
|
test_ln_s_add dir/subdir subdirlink &&
|
|
|
|
test_ln_s_add subdir/ind2 dir/link-to-child &&
|
|
|
|
test_ln_s_add dir/link-to-child link-to-down-link &&
|
|
|
|
test_ln_s_add dir/.. up-down &&
|
|
|
|
test_ln_s_add dir/../ up-down-trailing &&
|
|
|
|
test_ln_s_add dir/../morx up-down-file &&
|
|
|
|
test_ln_s_add dir/../../morx up-up-down-file &&
|
|
|
|
test_ln_s_add subdirlink/../../morx up-two-down-file &&
|
|
|
|
test_ln_s_add loop1 loop2 &&
|
|
|
|
test_ln_s_add loop2 loop1 &&
|
|
|
|
git add morx dir/subdir/ind2 dir/ind1 &&
|
|
|
|
git commit -am "test" &&
|
|
|
|
echo $hello_sha1 blob $hello_size >found
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' '
|
|
|
|
echo HEAD:morx | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual &&
|
|
|
|
echo HEAD:nope missing >expect &&
|
|
|
|
echo HEAD:nope | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, same-dir links' '
|
|
|
|
echo HEAD:same-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, links to dirs' '
|
|
|
|
echo HEAD:link-to-dir/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for broken in-repo, same-dir links' '
|
|
|
|
echo dangling 25 >expect &&
|
|
|
|
echo HEAD:broken-same-dir-link >>expect &&
|
|
|
|
echo HEAD:broken-same-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' '
|
|
|
|
echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for parent-dir links' '
|
|
|
|
echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual &&
|
|
|
|
echo notdir 29 >expect &&
|
|
|
|
echo HEAD:dir/parent-dir-link/nope >>expect &&
|
|
|
|
echo HEAD:dir/parent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' '
|
|
|
|
echo dangling 22 >expect &&
|
|
|
|
echo HEAD:dir/link-dir/nope >>expect &&
|
|
|
|
echo HEAD:dir/link-dir/nope | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:dir/link-dir/morx | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual &&
|
|
|
|
echo dangling 27 >expect &&
|
|
|
|
echo HEAD:dir/broken-link-in-dir >>expect &&
|
|
|
|
echo HEAD:dir/broken-link-in-dir | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for ../.. links' '
|
|
|
|
echo notdir 41 >expect &&
|
|
|
|
echo HEAD:dir/subdir/grandparent-dir-link/nope >>expect &&
|
|
|
|
echo HEAD:dir/subdir/grandparent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:dir/subdir/grandparent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual &&
|
|
|
|
echo HEAD:dir/subdir/parent-dir-link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/ links' '
|
|
|
|
echo dangling 17 >expect &&
|
|
|
|
echo HEAD:dirlink/morx >>expect &&
|
|
|
|
echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo $hello_sha1 blob $hello_size >expect &&
|
|
|
|
echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/subdir links' '
|
|
|
|
echo dangling 20 >expect &&
|
|
|
|
echo HEAD:subdirlink/morx >>expect &&
|
|
|
|
echo HEAD:subdirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:subdirlink/ind2 | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir ->subdir links' '
|
|
|
|
echo notdir 27 >expect &&
|
|
|
|
echo HEAD:dir/link-to-child/morx >>expect &&
|
|
|
|
echo HEAD:dir/link-to-child/morx | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:dir/link-to-child | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual &&
|
|
|
|
echo HEAD:link-to-down-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks' '
|
|
|
|
echo symlink 8 >expect &&
|
|
|
|
echo ../fleem >>expect &&
|
|
|
|
echo HEAD:out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo symlink 2 >expect &&
|
|
|
|
echo .. >>expect &&
|
|
|
|
echo HEAD:out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in dirs' '
|
|
|
|
echo symlink 9 >expect &&
|
|
|
|
echo ../escape >>expect &&
|
|
|
|
echo HEAD:dir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo symlink 2 >expect &&
|
|
|
|
echo .. >>expect &&
|
|
|
|
echo HEAD:dir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in subdirs' '
|
|
|
|
echo symlink 15 >expect &&
|
|
|
|
echo ../great-escape >>expect &&
|
|
|
|
echo HEAD:dir/subdir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo symlink 2 >expect &&
|
|
|
|
echo .. >>expect &&
|
|
|
|
echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo symlink 3 >expect &&
|
|
|
|
echo ../ >>expect &&
|
|
|
|
echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '
|
|
|
|
echo HEAD: | git cat-file --batch-check >expect &&
|
|
|
|
echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual &&
|
|
|
|
echo symlink 7 >expect &&
|
|
|
|
echo ../morx >>expect &&
|
|
|
|
echo HEAD:up-up-down-file | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
echo HEAD:up-two-down-file | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp found actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' '
|
|
|
|
echo loop 10 >expect &&
|
|
|
|
echo HEAD:loop1 >>expect &&
|
|
|
|
echo HEAD:loop1 | git cat-file --batch-check --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' '
|
|
|
|
echo HEAD:morx | git cat-file --batch >expect &&
|
|
|
|
echo HEAD:morx | git cat-file --batch --follow-symlinks >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
2015-06-01 21:45:16 +02:00
|
|
|
|
2015-06-22 12:45:59 +02:00
|
|
|
test_expect_success 'cat-file --batch-all-objects shows all objects' '
|
2015-06-22 13:06:32 +02:00
|
|
|
# make new repos so we know the full set of objects; we will
|
2015-06-22 12:45:59 +02:00
|
|
|
# also make sure that there are some packed and some loose
|
2018-08-11 01:16:40 +02:00
|
|
|
# objects, some referenced and some not, some duplicates, and that
|
|
|
|
# there are some available only via alternates.
|
2015-06-22 12:45:59 +02:00
|
|
|
git init all-one &&
|
|
|
|
(
|
|
|
|
cd all-one &&
|
|
|
|
echo content >file &&
|
|
|
|
git add file &&
|
|
|
|
git commit -qm base &&
|
|
|
|
git rev-parse HEAD HEAD^{tree} HEAD:file &&
|
|
|
|
git repack -ad &&
|
|
|
|
echo not-cloned | git hash-object -w --stdin
|
|
|
|
) >expect.unsorted &&
|
|
|
|
git clone -s all-one all-two &&
|
|
|
|
(
|
|
|
|
cd all-two &&
|
|
|
|
echo local-unref | git hash-object -w --stdin
|
|
|
|
) >>expect.unsorted &&
|
2018-08-11 01:16:40 +02:00
|
|
|
git -C all-two rev-parse HEAD:file |
|
|
|
|
git -C all-two pack-objects .git/objects/pack/pack &&
|
2015-06-22 12:45:59 +02:00
|
|
|
sort <expect.unsorted >expect &&
|
|
|
|
git -C all-two cat-file --batch-all-objects \
|
2015-06-22 13:06:32 +02:00
|
|
|
--batch-check="%(objectname)" >actual &&
|
2015-06-22 12:45:59 +02:00
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
cat-file: support "unordered" output for --batch-all-objects
If you're going to access the contents of every object in a
packfile, it's generally much more efficient to do so in
pack order, rather than in hash order. That increases the
locality of access within the packfile, which in turn is
friendlier to the delta base cache, since the packfile puts
related deltas next to each other. By contrast, hash order
is effectively random, since the sha1 has no discernible
relationship to the content.
This patch introduces an "--unordered" option to cat-file
which iterates over packs in pack-order under the hood. You
can see the results when dumping all of the file content:
$ time ./git cat-file --batch-all-objects --buffer --batch | wc -c
6883195596
real 0m44.491s
user 0m42.902s
sys 0m5.230s
$ time ./git cat-file --unordered \
--batch-all-objects --buffer --batch | wc -c
6883195596
real 0m6.075s
user 0m4.774s
sys 0m3.548s
Same output, different order, way faster. The same speed-up
applies even if you end up accessing the object content in a
different process, like:
git cat-file --batch-all-objects --buffer --batch-check |
grep blob |
git cat-file --batch='%(objectname) %(rest)' |
wc -c
Adding "--unordered" to the first command drops the runtime
in git.git from 24s to 3.5s.
Side note: there are actually further speedups available
for doing it all in-process now. Since we are outputting
the object content during the actual pack iteration, we
know where to find the object and could skip the extra
lookup done by oid_object_info(). This patch stops short
of that optimization since the underlying API isn't ready
for us to make those sorts of direct requests.
So if --unordered is so much better, why not make it the
default? Two reasons:
1. We've promised in the documentation that --batch-all-objects
outputs in hash order. Since cat-file is plumbing,
people may be relying on that default, and we can't
change it.
2. It's actually _slower_ for some cases. We have to
compute the pack revindex to walk in pack order. And
our de-duplication step uses an oidset, rather than a
sort-and-dedup, which can end up being more expensive.
If we're just accessing the type and size of each
object, for example, like:
git cat-file --batch-all-objects --buffer --batch-check
my best-of-five warm cache timings go from 900ms to
1100ms using --unordered. Though it's possible in a
cold-cache or under memory pressure that we could do
better, since we'd have better locality within the
packfile.
And one final question: why is it "--unordered" and not
"--pack-order"? The answer is again two-fold:
1. "pack order" isn't a well-defined thing across the
whole set of objects. We're hitting loose objects, as
well as objects in multiple packs, and the only
ordering we're promising is _within_ a single pack. The
rest is apparently random.
2. The point here is optimization. So we don't want to
promise any particular ordering, but only to say that
we will choose an ordering which is likely to be
efficient for accessing the object content. That leaves
the door open for further changes in the future without
having to add another compatibility option.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-11 01:24:57 +02:00
|
|
|
# The only user-visible difference is that the objects are no longer sorted,
|
|
|
|
# and the resulting sort order is undefined. So we can only check that it
|
|
|
|
# produces the same objects as the ordered case, but that at least exercises
|
|
|
|
# the code.
|
|
|
|
test_expect_success 'cat-file --unordered works' '
|
|
|
|
git -C all-two cat-file --batch-all-objects --unordered \
|
|
|
|
--batch-check="%(objectname)" >actual.unsorted &&
|
|
|
|
sort <actual.unsorted >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2021-06-03 18:29:25 +02:00
|
|
|
test_expect_success 'set up object list for --batch-all-objects tests' '
|
|
|
|
git -C all-two cat-file --batch-all-objects --batch-check="%(objectname)" >objects
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch="%(objectname)" with --batch-all-objects will work' '
|
|
|
|
git -C all-two cat-file --batch="%(objectname)" <objects >expect &&
|
|
|
|
git -C all-two cat-file --batch-all-objects --batch="%(objectname)" >actual &&
|
|
|
|
cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch="%(rest)" with --batch-all-objects will work' '
|
|
|
|
git -C all-two cat-file --batch="%(rest)" <objects >expect &&
|
|
|
|
git -C all-two cat-file --batch-all-objects --batch="%(rest)" >actual &&
|
|
|
|
cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch="batman" with --batch-all-objects will work' '
|
|
|
|
git -C all-two cat-file --batch="batman" <objects >expect &&
|
|
|
|
git -C all-two cat-file --batch-all-objects --batch="batman" >actual &&
|
|
|
|
cmp expect actual
|
|
|
|
'
|
|
|
|
|
cat-file: disable refs/replace with --batch-all-objects
When we're enumerating all objects in the object database, it doesn't
make sense to respect refs/replace. The point of this option is to
enumerate all of the objects in the database at a low level. By
definition we'd already show the replacement object's contents (under
its real oid), and showing those contents under another oid is almost
certainly working against what the user is trying to do.
Note that you could make the same argument for something like:
git show-index <foo.idx |
awk '{print $2}' |
git cat-file --batch
but there we can't know in cat-file exactly what the user intended,
because we don't know the source of the input. They could be trying to
do low-level debugging, or they could be doing something more high-level
(e.g., imagine a porcelain built around cat-file for its object
accesses). So in those cases, we'll have to rely on the user specifying
"git --no-replace-objects" to tell us what to do.
One _could_ make an argument that "cat-file --batch" is sufficiently
low-level plumbing that it should not respect replace-objects at all
(and the caller should do any replacement if they want it). But we have
been doing so for some time. The history is a little tangled:
- looking back as far as v1.6.6, we would not respect replace refs for
--batch-check, but would for --batch (because the former used
sha1_object_info(), and the replace mechanism only affected actual
object reads)
- this discrepancy was made even weirder by 98e2092b50 (cat-file:
teach --batch to stream blob objects, 2013-07-10), where we always
output the header using the --batch-check code, and then printed the
object separately. This could lead to "cat-file --batch" dying (when
it notices the size or type changed for a non-blob object) or even
producing bogus output (in streaming mode, we didn't notice that we
wrote the wrong number of bytes).
- that persisted until 1f7117ef7a (sha1_file: perform object
replacement in sha1_object_info_extended(), 2013-12-11), which then
respected replace refs for both forms.
So it has worked reliably this way for over 7 years, and we should make
sure it continues to do so. That could also be an argument that
--batch-all-objects should not change behavior (which this patch is
doing), but I really consider the current behavior to be an unintended
bug. It's a side effect of how the code is implemented (feeding the oids
back into oid_object_info() rather than looking at what we found while
reading the loose and packed object storage).
The implementation is straight-forward: we just disable the global
read_replace_refs flag when we're in --batch-all-objects mode. It would
perhaps be a little cleaner to change the flag we pass to
oid_object_info_extended(), but that's not enough. We also read objects
via read_object_file() and stream_blob_to_fd(). The former could switch
to its _extended() form, but the streaming code has no mechanism for
disabling replace refs. Setting the global flag works, and as a bonus,
it's impossible to have any "oops, we're sometimes replacing the object
and sometimes not" bugs in the output (like the ones caused by
98e2092b50 above).
The tests here cover the regular-input and --batch-all-objects cases,
for both --batch-check and --batch. There is a test in t6050 that covers
the regular-input case with --batch already, but this new one goes much
further in actually verifying the output (plus covering --batch-check
explicitly). This is perhaps a little overkill and the tests would be
simpler just covering --batch-check, but I wanted to make sure we're
checking that --batch output is consistent between the header and the
content. The global-flag technique used here makes that easy to get
right, but this is future-proofing us against regressions.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-05 22:36:07 +02:00
|
|
|
test_expect_success 'set up replacement object' '
|
|
|
|
orig=$(git rev-parse HEAD) &&
|
|
|
|
git cat-file commit $orig >orig &&
|
|
|
|
{
|
|
|
|
cat orig &&
|
|
|
|
echo extra
|
|
|
|
} >fake &&
|
|
|
|
fake=$(git hash-object -t commit -w fake) &&
|
|
|
|
orig_size=$(git cat-file -s $orig) &&
|
|
|
|
fake_size=$(git cat-file -s $fake) &&
|
|
|
|
git replace $orig $fake
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch respects replace objects' '
|
|
|
|
git cat-file --batch >actual <<-EOF &&
|
|
|
|
$orig
|
|
|
|
EOF
|
|
|
|
{
|
|
|
|
echo "$orig commit $fake_size" &&
|
|
|
|
cat fake &&
|
|
|
|
echo
|
|
|
|
} >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch-check respects replace objects' '
|
|
|
|
git cat-file --batch-check >actual <<-EOF &&
|
|
|
|
$orig
|
|
|
|
EOF
|
|
|
|
echo "$orig commit $fake_size" >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
# Pull the entry for object with oid "$1" out of the output of
|
|
|
|
# "cat-file --batch", including its object content (which requires
|
|
|
|
# parsing and reading a set amount of bytes, hence perl).
|
|
|
|
extract_batch_output () {
|
|
|
|
perl -ne '
|
|
|
|
BEGIN { $oid = shift }
|
|
|
|
if (/^$oid \S+ (\d+)$/) {
|
|
|
|
print;
|
|
|
|
read STDIN, my $buf, $1;
|
|
|
|
print $buf;
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
' "$@"
|
|
|
|
}
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
|
|
|
|
git cat-file --batch-all-objects --batch >actual.raw &&
|
|
|
|
extract_batch_output $orig <actual.raw >actual &&
|
|
|
|
{
|
|
|
|
echo "$orig commit $orig_size" &&
|
|
|
|
cat orig &&
|
|
|
|
echo
|
|
|
|
} >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace' '
|
|
|
|
git cat-file --batch-all-objects --batch-check >actual.raw &&
|
|
|
|
grep ^$orig actual.raw >actual &&
|
|
|
|
echo "$orig commit $orig_size" >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
cat-file: add --batch-command mode
Add a new flag --batch-command that accepts commands and arguments
from stdin, similar to git-update-ref --stdin.
At GitLab, we use a pair of long running cat-file processes when
accessing object content. One for iterating over object metadata with
--batch-check, and the other to grab object contents with --batch.
However, if we had --batch-command, we wouldn't need to keep both
processes around, and instead just have one --batch-command process
where we can flip between getting object info, and getting object
contents. Since we have a pair of cat-file processes per repository,
this means we can get rid of roughly half of long lived git cat-file
processes. Given there are many repositories being accessed at any given
time, this can lead to huge savings.
git cat-file --batch-command
will enter an interactive command mode whereby the user can enter in
commands and their arguments that get queued in memory:
<command1> [arg1] [arg2] LF
<command2> [arg1] [arg2] LF
When --buffer mode is used, commands will be queued in memory until a
flush command is issued that execute them:
flush LF
The reason for a flush command is that when a consumer process (A)
talks to a git cat-file process (B) and interactively writes to and
reads from it in --buffer mode, (A) needs to be able to control when
the buffer is flushed to stdout.
Currently, from (A)'s perspective, the only way is to either
1. kill (B)'s process
2. send an invalid object to stdin.
1. is not ideal from a performance perspective as it will require
spawning a new cat-file process each time, and 2. is hacky and not a
good long term solution.
With this mechanism of queueing up commands and letting (A) issue a
flush command, process (A) can control when the buffer is flushed and
can guarantee it will receive all of the output when in --buffer mode.
--batch-command also will not allow (B) to flush to stdout until a flush
is received.
This patch adds the basic structure for adding command which can be
extended in the future to add more commands. It also adds the following
two commands (on top of the flush command):
contents <object> LF
info <object> LF
The contents command takes an <object> argument and prints out the object
contents.
The info command takes an <object> argument and prints out the object
metadata.
These can be used in the following way with --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
flush LF
info <object> LF
flush LF
When used without --buffer:
info <object> LF
contents <object> LF
contents <object> LF
info <object> LF
info <object> LF
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: John Cai <johncai86@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-18 19:23:14 +01:00
|
|
|
test_expect_success 'batch-command empty command' '
|
|
|
|
echo "" >cmd &&
|
|
|
|
test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
|
|
|
|
grep "^fatal:.*empty command in input.*" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'batch-command whitespace before command' '
|
|
|
|
echo " info deadbeef" >cmd &&
|
|
|
|
test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
|
|
|
|
grep "^fatal:.*whitespace before command.*" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'batch-command unknown command' '
|
|
|
|
echo unknown_command >cmd &&
|
|
|
|
test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
|
|
|
|
grep "^fatal:.*unknown command.*" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'batch-command missing arguments' '
|
|
|
|
echo "info" >cmd &&
|
|
|
|
test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
|
|
|
|
grep "^fatal:.*info requires arguments.*" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'batch-command flush with arguments' '
|
|
|
|
echo "flush arg" >cmd &&
|
|
|
|
test_expect_code 128 git cat-file --batch-command --buffer <cmd 2>err &&
|
|
|
|
grep "^fatal:.*flush takes no arguments.*" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'batch-command flush without --buffer' '
|
|
|
|
echo "flush" >cmd &&
|
|
|
|
test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
|
|
|
|
grep "^fatal:.*flush is only for --buffer mode.*" err
|
|
|
|
'
|
cat-file: disable refs/replace with --batch-all-objects
When we're enumerating all objects in the object database, it doesn't
make sense to respect refs/replace. The point of this option is to
enumerate all of the objects in the database at a low level. By
definition we'd already show the replacement object's contents (under
its real oid), and showing those contents under another oid is almost
certainly working against what the user is trying to do.
Note that you could make the same argument for something like:
git show-index <foo.idx |
awk '{print $2}' |
git cat-file --batch
but there we can't know in cat-file exactly what the user intended,
because we don't know the source of the input. They could be trying to
do low-level debugging, or they could be doing something more high-level
(e.g., imagine a porcelain built around cat-file for its object
accesses). So in those cases, we'll have to rely on the user specifying
"git --no-replace-objects" to tell us what to do.
One _could_ make an argument that "cat-file --batch" is sufficiently
low-level plumbing that it should not respect replace-objects at all
(and the caller should do any replacement if they want it). But we have
been doing so for some time. The history is a little tangled:
- looking back as far as v1.6.6, we would not respect replace refs for
--batch-check, but would for --batch (because the former used
sha1_object_info(), and the replace mechanism only affected actual
object reads)
- this discrepancy was made even weirder by 98e2092b50 (cat-file:
teach --batch to stream blob objects, 2013-07-10), where we always
output the header using the --batch-check code, and then printed the
object separately. This could lead to "cat-file --batch" dying (when
it notices the size or type changed for a non-blob object) or even
producing bogus output (in streaming mode, we didn't notice that we
wrote the wrong number of bytes).
- that persisted until 1f7117ef7a (sha1_file: perform object
replacement in sha1_object_info_extended(), 2013-12-11), which then
respected replace refs for both forms.
So it has worked reliably this way for over 7 years, and we should make
sure it continues to do so. That could also be an argument that
--batch-all-objects should not change behavior (which this patch is
doing), but I really consider the current behavior to be an unintended
bug. It's a side effect of how the code is implemented (feeding the oids
back into oid_object_info() rather than looking at what we found while
reading the loose and packed object storage).
The implementation is straight-forward: we just disable the global
read_replace_refs flag when we're in --batch-all-objects mode. It would
perhaps be a little cleaner to change the flag we pass to
oid_object_info_extended(), but that's not enough. We also read objects
via read_object_file() and stream_blob_to_fd(). The former could switch
to its _extended() form, but the streaming code has no mechanism for
disabling replace refs. Setting the global flag works, and as a bonus,
it's impossible to have any "oops, we're sometimes replacing the object
and sometimes not" bugs in the output (like the ones caused by
98e2092b50 above).
The tests here cover the regular-input and --batch-all-objects cases,
for both --batch-check and --batch. There is a test in t6050 that covers
the regular-input case with --batch already, but this new one goes much
further in actually verifying the output (plus covering --batch-check
explicitly). This is perhaps a little overkill and the tests would be
simpler just covering --batch-check, but I wanted to make sure we're
checking that --batch output is consistent between the header and the
content. The global-flag technique used here makes that easy to get
right, but this is future-proofing us against regressions.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-05 22:36:07 +02:00
|
|
|
|
2008-04-23 21:17:43 +02:00
|
|
|
test_done
|