2016-10-26 17:19:16 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
2018-07-10 18:48:02 +00:00
|
|
|
. "$(dirname "$0")/testlib.sh"
|
2016-10-26 17:19:16 +00:00
|
|
|
|
|
|
|
# HACK(taylor): git uses ".g<hash>" in the version name to signal that it is
|
|
|
|
# from the "next" branch, which is the only (current) version of Git that has
|
|
|
|
# support for the filter protocol.
|
|
|
|
#
|
2016-11-22 09:01:14 +00:00
|
|
|
ensure_git_version_isnt $VERSION_LOWER "2.11.0"
|
2016-10-26 17:19:16 +00:00
|
|
|
|
|
|
|
begin_test "filter process: checking out a branch"
|
|
|
|
(
|
|
|
|
set -e
|
|
|
|
|
|
|
|
reponame="filter_process_checkout"
|
|
|
|
setup_remote_repo "$reponame"
|
|
|
|
clone_repo "$reponame" repo
|
|
|
|
|
|
|
|
git lfs track "*.dat"
|
|
|
|
git add .gitattributes
|
|
|
|
git commit -m "initial commit"
|
|
|
|
|
|
|
|
contents_a="contents_a"
|
|
|
|
contents_a_oid="$(calc_oid $contents_a)"
|
2018-09-10 14:57:10 +00:00
|
|
|
printf "%s" "$contents_a" > a.dat
|
2016-10-26 17:19:16 +00:00
|
|
|
|
|
|
|
git add a.dat
|
|
|
|
git commit -m "add a.dat"
|
|
|
|
|
|
|
|
git checkout -b b
|
|
|
|
|
|
|
|
contents_b="contents_b"
|
|
|
|
contents_b_oid="$(calc_oid $contents_b)"
|
2018-09-10 14:57:10 +00:00
|
|
|
printf "%s" "$contents_b" > b.dat
|
2016-10-26 17:19:16 +00:00
|
|
|
|
|
|
|
git add b.dat
|
|
|
|
git commit -m "add b.dat"
|
|
|
|
|
|
|
|
git push origin --all
|
|
|
|
|
|
|
|
pushd ..
|
2016-11-10 18:26:07 +00:00
|
|
|
# Git will choose filter.lfs.process over `filter.lfs.clean` and
|
|
|
|
# `filter.lfs.smudge`
|
2017-08-12 04:18:56 +00:00
|
|
|
GIT_TRACE_PACKET=1 git \
|
2016-11-08 20:05:12 +00:00
|
|
|
-c "filter.lfs.process=git-lfs filter-process" \
|
2016-11-10 18:26:07 +00:00
|
|
|
-c "filter.lfs.clean=false"\
|
|
|
|
-c "filter.lfs.smudge=false" \
|
2016-10-26 17:19:16 +00:00
|
|
|
-c "filter.lfs.required=true" \
|
|
|
|
clone "$GITSERVER/$reponame" "$reponame-assert"
|
|
|
|
|
|
|
|
cd "$reponame-assert"
|
|
|
|
|
2020-06-29 16:18:57 +00:00
|
|
|
# Assert that we are on the "main" branch, and have a.dat
|
|
|
|
[ "main" = "$(git rev-parse --abbrev-ref HEAD)" ]
|
2016-10-26 17:19:16 +00:00
|
|
|
[ "$contents_a" = "$(cat a.dat)" ]
|
2020-06-29 16:18:57 +00:00
|
|
|
assert_pointer "main" "a.dat" "$contents_a_oid" 10
|
2016-10-26 17:19:16 +00:00
|
|
|
|
|
|
|
git checkout b
|
|
|
|
|
|
|
|
# Assert that we are on the "b" branch, and have b.dat
|
|
|
|
[ "b" = "$(git rev-parse --abbrev-ref HEAD)" ]
|
|
|
|
[ "$contents_b" = "$(cat b.dat)" ]
|
|
|
|
assert_pointer "b" "b.dat" "$contents_b_oid" 10
|
|
|
|
popd
|
|
|
|
)
|
|
|
|
end_test
|
2016-11-02 23:07:35 +00:00
|
|
|
|
|
|
|
begin_test "filter process: adding a file"
|
|
|
|
(
|
|
|
|
set -e
|
|
|
|
|
|
|
|
reponame="filter_process_add"
|
|
|
|
setup_remote_repo "$reponame"
|
|
|
|
clone_repo "$reponame" "$reponame"
|
|
|
|
|
|
|
|
git lfs track "*.dat"
|
|
|
|
git add .gitattributes
|
|
|
|
git commit -m "initial commit"
|
|
|
|
|
|
|
|
contents="contents"
|
|
|
|
contents_oid="$(calc_oid "$contents")"
|
2018-09-10 14:57:10 +00:00
|
|
|
printf "%s" "$contents" > a.dat
|
2016-11-02 23:07:35 +00:00
|
|
|
|
|
|
|
git add a.dat
|
|
|
|
|
|
|
|
expected="$(pointer "$contents_oid" "${#contents}")"
|
|
|
|
got="$(git cat-file -p :a.dat)"
|
|
|
|
|
|
|
|
diff -u <(echo "$expected") <(echo "$got")
|
|
|
|
)
|
|
|
|
end_test
|
2016-11-22 08:51:55 +00:00
|
|
|
|
|
|
|
# https://github.com/git-lfs/git-lfs/issues/1697
|
|
|
|
begin_test "filter process: add a file with 1024 bytes"
|
|
|
|
(
|
|
|
|
set -e
|
|
|
|
|
2016-11-22 11:32:39 +00:00
|
|
|
mkdir repo-issue-1697
|
|
|
|
cd repo-issue-1697
|
2016-11-22 08:51:55 +00:00
|
|
|
git init
|
|
|
|
git lfs track "*.dat"
|
|
|
|
dd if=/dev/zero of=first.dat bs=1024 count=1
|
|
|
|
printf "any contents" > second.dat
|
|
|
|
git add .
|
|
|
|
)
|
|
|
|
end_test
|
|
|
|
|
filter-process: avoid hang when using git hash-object --stdin
When we use git hash-object --stdin with the --path option, Git applies
filters to the object, so Git LFS is invoked. However, if the object
provided is less than 1024 bytes in size, we would hang. This occurred
because of our packet reader didn't quite implement the io.Reader
interface completely: if it returned a non-zero value and io.EOF, the
next call to Read would not return 0 and io.EOF. Instead, it would try
to read from stdin, which would not be sending us more data until we
provided a response, so we would hang.
To solve this, keep track of the EOF and always return it on subsequent
Read calls. In addition, don't process the callback to write the file
in this case, since we don't actually want to write into the working
tree.
2019-11-04 19:20:45 +00:00
|
|
|
begin_test "filter process: hash-object --stdin --path does not hang"
|
|
|
|
(
|
|
|
|
set -e
|
2016-11-22 08:51:55 +00:00
|
|
|
|
filter-process: avoid hang when using git hash-object --stdin
When we use git hash-object --stdin with the --path option, Git applies
filters to the object, so Git LFS is invoked. However, if the object
provided is less than 1024 bytes in size, we would hang. This occurred
because of our packet reader didn't quite implement the io.Reader
interface completely: if it returned a non-zero value and io.EOF, the
next call to Read would not return 0 and io.EOF. Instead, it would try
to read from stdin, which would not be sending us more data until we
provided a response, so we would hang.
To solve this, keep track of the EOF and always return it on subsequent
Read calls. In addition, don't process the callback to write the file
in this case, since we don't actually want to write into the working
tree.
2019-11-04 19:20:45 +00:00
|
|
|
mkdir repo-hash-object
|
|
|
|
cd repo-hash-object
|
|
|
|
git init
|
|
|
|
git lfs track "*.dat"
|
|
|
|
contents="test"
|
|
|
|
contents_oid="$(calc_oid "$contents")"
|
|
|
|
expected=$(pointer "$contents_oid" 4 | git hash-object --stdin)
|
|
|
|
|
|
|
|
dd if=/dev/zero of=first.dat bs=1000 count=1
|
|
|
|
echo a > second.dat
|
|
|
|
# Works for existing file longer than this one.
|
|
|
|
output=$(printf test | git hash-object --path first.dat --stdin)
|
|
|
|
[ "$expected" = "$output" ]
|
|
|
|
# Works for existing file shorter than this one.
|
|
|
|
output=$(printf test | git hash-object --path second.dat --stdin)
|
|
|
|
[ "$expected" = "$output" ]
|
|
|
|
# Works for absent file.
|
|
|
|
output=$(printf test | git hash-object --path third.dat --stdin)
|
|
|
|
[ "$expected" = "$output" ]
|
|
|
|
|
|
|
|
dd if=/dev/zero of=large.dat bs=65537 count=1
|
|
|
|
oid=$(calc_oid_file large.dat)
|
|
|
|
expected=$(pointer "$oid" 65537 | git hash-object --stdin)
|
|
|
|
output=$(git hash-object --path third.dat --stdin <large.dat)
|
|
|
|
[ "$expected" = "$output" ]
|
|
|
|
git add .
|
|
|
|
)
|
|
|
|
end_test
|
smudge: honor GIT_LFS_SKIP_SMUDGE with checkout-index
In most cases, users use a relatively modern version of Git which
supports the filter-process code and delayed smudging. This is valuable
because it makes things much faster. However, it also uses a different
code path from the non-delayed path. This non-delayed path is also used
by git checkout-index.
The non-delayed path doesn't work properly, however, if the data is
already on disk. In such a case, we simply ask the smudge filter not to
download the data, but since it's already on disk, we feed it out
anyway.
Let's solve this by simply not invoking the filter and emitting the
pointer if we've asked to skip. We do the same thing if the file
doesn't match the filter, since the comment at the top of the function
states that's what's supposed to happen here as well.
Once we've done that, the variable download is always true, so remove
all the code which considers that it might be false to simplify the code
somewhat.
2022-02-07 16:00:01 +00:00
|
|
|
|
|
|
|
begin_test "filter process: checking out a branch with --skip-smudge and checkout-index"
|
|
|
|
(
|
|
|
|
set -e
|
|
|
|
|
|
|
|
reponame="filter-process-skip-smudge-checkout-index"
|
|
|
|
setup_remote_repo "$reponame"
|
|
|
|
clone_repo "$reponame" "$reponame"
|
|
|
|
|
|
|
|
git lfs track "*.dat"
|
|
|
|
git add .gitattributes
|
|
|
|
git commit -m "initial commit"
|
|
|
|
|
|
|
|
contents_a="contents_a"
|
|
|
|
contents_a_oid="$(calc_oid $contents_a)"
|
|
|
|
printf "%s" "$contents_a" > a.dat
|
|
|
|
|
|
|
|
git add a.dat
|
|
|
|
git commit -m "add a.dat"
|
|
|
|
|
|
|
|
git checkout -b b
|
|
|
|
|
|
|
|
contents_b="contents_b"
|
|
|
|
contents_b_oid="$(calc_oid $contents_b)"
|
|
|
|
printf "%s" "$contents_b" > b.dat
|
|
|
|
|
|
|
|
git add b.dat
|
|
|
|
git commit -m "add b.dat"
|
|
|
|
|
|
|
|
git lfs install --local --skip-smudge
|
|
|
|
|
|
|
|
git checkout main
|
|
|
|
|
|
|
|
rm a.dat
|
|
|
|
git checkout-index -af
|
|
|
|
git lfs pointer --check --file a.dat
|
|
|
|
|
|
|
|
assert_pointer "main" "a.dat" "$contents_a_oid" 10
|
|
|
|
|
|
|
|
git checkout b
|
|
|
|
|
|
|
|
rm *.dat
|
|
|
|
git checkout-index -af
|
|
|
|
git lfs pointer --check --file a.dat
|
|
|
|
git lfs pointer --check --file b.dat
|
|
|
|
|
|
|
|
# Assert that we are on the "b" branch, and have b.dat
|
|
|
|
assert_pointer "b" "b.dat" "$contents_b_oid" 10
|
|
|
|
)
|
|
|
|
end_test
|